xref: /openbmc/qemu/linux-user/main.c (revision 851ed57d7a24ddf234a90b5bb196a143c84c10bc)
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"
4116aa8eaaSPhilippe Mathieu-Daudé #include "user/guest-base.h"
4263c91552SPaolo Bonzini #include "exec/exec-all.h"
4385b4fa0cSPeter Maydell #include "exec/gdbstub.h"
44d96bf49bSAlex Bennée #include "gdbstub/user.h"
45d7ec12f8SRichard Henderson #include "tcg/startup.h"
461de7afc9SPaolo Bonzini #include "qemu/timer.h"
471de7afc9SPaolo Bonzini #include "qemu/envlist.h"
485ebdd774SRichard Henderson #include "qemu/guest-random.h"
49d8fd2954SPaul Brook #include "elf.h"
506533dd6eSLluís Vilanova #include "trace/control.h"
51542ca434SLaurent Vivier #include "target_elf.h"
52cd71c089SLaurent Vivier #include "cpu_loop-common.h"
53a573e9baSRichard Henderson #include "crypto/init.h"
54c093364fSOwen Anderson #include "fd-trans.h"
552113aed6SPeter Maydell #include "signal-common.h"
563ad0a769SPeter Maydell #include "loader.h"
575423e6d3SPeter Maydell #include "user-mmap.h"
58327b75a4SIlya Leoshkevich #include "tcg/perf.h"
59ff8a8bbcSRichard Henderson #include "exec/page-vary.h"
6004a6dfebSaurel32 
61e4a4aaa5SRichard Henderson #ifdef CONFIG_SEMIHOSTING
62e4a4aaa5SRichard Henderson #include "semihosting/semihost.h"
63e4a4aaa5SRichard Henderson #endif
64e4a4aaa5SRichard Henderson 
656e1c0d7bSLaurent Vivier #ifndef AT_FLAGS_PRESERVE_ARGV0
666e1c0d7bSLaurent Vivier #define AT_FLAGS_PRESERVE_ARGV0_BIT 0
676e1c0d7bSLaurent Vivier #define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
686e1c0d7bSLaurent Vivier #endif
696e1c0d7bSLaurent Vivier 
70d088d664Saurel32 char *exec_path;
71258bec39SHelge Deller char real_exec_path[PATH_MAX];
72d088d664Saurel32 
733cfb0456SPeter Maydell static bool opt_one_insn_per_tb;
748cb76755SStefan Weil static const char *argv0;
75fcedd920SAlex Bennée static const char *gdbstub;
768cb76755SStefan Weil static envlist_t *envlist;
7751fb256aSAndreas Färber static const char *cpu_model;
782278b939SIgor Mammedov static const char *cpu_type;
795ebdd774SRichard Henderson static const char *seed_optarg;
80379f6698SPaul Brook unsigned long mmap_min_addr;
815ca870b9SRichard Henderson uintptr_t guest_base;
82e307c192SRichard Henderson bool have_guest_base;
83120a9848SPaolo Bonzini 
84288e65b9SAlexander Graf /*
854b25a506SJosh Kunz  * Used to implement backwards-compatibility for the `-strace`, and
864b25a506SJosh Kunz  * QEMU_STRACE options. Without this, the QEMU_LOG can be overwritten by
874b25a506SJosh Kunz  * -strace, or vice versa.
884b25a506SJosh Kunz  */
894b25a506SJosh Kunz static bool enable_strace;
904b25a506SJosh Kunz 
914b25a506SJosh Kunz /*
924b25a506SJosh Kunz  * The last log mask given by the user in an environment variable or argument.
934b25a506SJosh Kunz  * Used to support command line arguments overriding environment variables.
944b25a506SJosh Kunz  */
954b25a506SJosh Kunz static int last_log_mask;
96b410253fSRichard Henderson static const char *last_log_filename;
974b25a506SJosh Kunz 
984b25a506SJosh Kunz /*
99288e65b9SAlexander Graf  * When running 32-on-64 we should make sure we can fit all of the possible
100288e65b9SAlexander Graf  * guest address space into a contiguous chunk of virtual host memory.
101288e65b9SAlexander Graf  *
102288e65b9SAlexander Graf  * This way we will never overlap with our own libraries or binaries or stack
103288e65b9SAlexander Graf  * or anything else that QEMU maps.
10418e80c55SRichard Henderson  *
10518e80c55SRichard Henderson  * Many cpus reserve the high bit (or more than one for some 64-bit cpus)
10618e80c55SRichard Henderson  * of the address for the kernel.  Some cpus rely on this and user space
10718e80c55SRichard Henderson  * uses the high bit(s) for pointer tagging and the like.  For them, we
10818e80c55SRichard Henderson  * must preserve the expected address space.
109288e65b9SAlexander Graf  */
11018e80c55SRichard Henderson #ifndef MAX_RESERVED_VA
11118e80c55SRichard Henderson # if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
11218e80c55SRichard Henderson #  if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \
11318e80c55SRichard Henderson       (TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
11495059f9cSRichard Henderson #   define MAX_RESERVED_VA(CPU)  0xfffffffful
115314992b1SAlexander Graf #  else
11695059f9cSRichard Henderson #   define MAX_RESERVED_VA(CPU)  ((1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1)
117314992b1SAlexander Graf #  endif
118288e65b9SAlexander Graf # else
1198f67b9c6SRichard Henderson #  define MAX_RESERVED_VA(CPU)  0
12018e80c55SRichard Henderson # endif
12118e80c55SRichard Henderson #endif
12218e80c55SRichard Henderson 
12368a1c816SPaul Brook unsigned long reserved_va;
1241b530a6dSaurel32 
125d03f9c32SMeador Inge static void usage(int exitcode);
126fc9c5412SJohannes Schauer 
1277ee2822cSPaolo Bonzini static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
128e586822aSRiku Voipio const char *qemu_uname_release;
129586314f2Sbellard 
1300a3346b5SHelge Deller #if !defined(TARGET_DEFAULT_STACK_SIZE)
1319de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
1329de5e440Sbellard    we allocate a bigger stack. Need a better solution, for example
1339de5e440Sbellard    by remapping the process stack directly at the right place */
1340a3346b5SHelge Deller #define TARGET_DEFAULT_STACK_SIZE	8 * 1024 * 1024UL
1350a3346b5SHelge Deller #endif
1360a3346b5SHelge Deller 
1370a3346b5SHelge Deller unsigned long guest_stack_size = TARGET_DEFAULT_STACK_SIZE;
13831e31b8aSbellard 
139d5975363Spbrook /***********************************************************/
140d5975363Spbrook /* Helper routines for implementing atomic operations.  */
141d5975363Spbrook 
142d5975363Spbrook /* Make sure everything is in a consistent state for calling fork().  */
fork_start(void)143d5975363Spbrook void fork_start(void)
144d5975363Spbrook {
14506065c45SPeter Maydell     start_exclusive();
146d032d1b4SRiku Voipio     mmap_fork_start();
147024949caSPeter Maydell     cpu_list_lock();
148f7e15affSAlex Bennée     qemu_plugin_user_prefork_lock();
1493d6ed98dSIlya Leoshkevich     gdbserver_fork_start();
150d5975363Spbrook }
151d5975363Spbrook 
fork_end(pid_t pid)1524edc98fcSIlya Leoshkevich void fork_end(pid_t pid)
153d5975363Spbrook {
1544edc98fcSIlya Leoshkevich     bool child = pid == 0;
1554edc98fcSIlya Leoshkevich 
156f7e15affSAlex Bennée     qemu_plugin_user_postfork(child);
157d032d1b4SRiku Voipio     mmap_fork_end(child);
158d5975363Spbrook     if (child) {
159bdc44640SAndreas Färber         CPUState *cpu, *next_cpu;
160d5975363Spbrook         /* Child processes created by fork() only have a single thread.
161d5975363Spbrook            Discard information about the parent threads.  */
162bdc44640SAndreas Färber         CPU_FOREACH_SAFE(cpu, next_cpu) {
163bdc44640SAndreas Färber             if (cpu != thread_cpu) {
1643c55dd58SPhilippe Mathieu-Daudé                 QTAILQ_REMOVE_RCU(&cpus_queue, cpu, node);
165bdc44640SAndreas Färber             }
166bdc44640SAndreas Färber         }
167267f685bSPaolo Bonzini         qemu_init_cpu_list();
168d4e1369aSIlya Leoshkevich         get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
169d5975363Spbrook     } else {
170267f685bSPaolo Bonzini         cpu_list_unlock();
171d5975363Spbrook     }
1726604b057SIlya Leoshkevich     gdbserver_fork_end(thread_cpu, pid);
1737de0816fSIlya Leoshkevich     /*
1747de0816fSIlya Leoshkevich      * qemu_init_cpu_list() reinitialized the child exclusive state, but we
1757de0816fSIlya Leoshkevich      * also need to keep current_cpu consistent, so call end_exclusive() for
1767de0816fSIlya Leoshkevich      * both child and parent.
1777de0816fSIlya Leoshkevich      */
1787de0816fSIlya Leoshkevich     end_exclusive();
179d5975363Spbrook }
180d5975363Spbrook 
181b44316fbSPeter Maydell __thread CPUState *thread_cpu;
18259faf6d6Sbellard 
qemu_cpu_is_self(CPUState * cpu)183178f9429SSergey Fedorov bool qemu_cpu_is_self(CPUState *cpu)
184178f9429SSergey Fedorov {
185178f9429SSergey Fedorov     return thread_cpu == cpu;
186178f9429SSergey Fedorov }
187178f9429SSergey Fedorov 
qemu_cpu_kick(CPUState * cpu)188178f9429SSergey Fedorov void qemu_cpu_kick(CPUState *cpu)
189178f9429SSergey Fedorov {
190178f9429SSergey Fedorov     cpu_exit(cpu);
191178f9429SSergey Fedorov }
192178f9429SSergey Fedorov 
task_settid(TaskState * ts)193edf8e2afSMika Westerberg void task_settid(TaskState *ts)
194edf8e2afSMika Westerberg {
195edf8e2afSMika Westerberg     if (ts->ts_tid == 0) {
196edf8e2afSMika Westerberg         ts->ts_tid = (pid_t)syscall(SYS_gettid);
197edf8e2afSMika Westerberg     }
198edf8e2afSMika Westerberg }
199edf8e2afSMika Westerberg 
stop_all_tasks(void)200edf8e2afSMika Westerberg void stop_all_tasks(void)
201edf8e2afSMika Westerberg {
202edf8e2afSMika Westerberg     /*
203edf8e2afSMika Westerberg      * We trust that when using NPTL, start_exclusive()
204edf8e2afSMika Westerberg      * handles thread stopping correctly.
205edf8e2afSMika Westerberg      */
206edf8e2afSMika Westerberg     start_exclusive();
207edf8e2afSMika Westerberg }
208edf8e2afSMika Westerberg 
209c3a92833Spbrook /* Assumes contents are already zeroed.  */
init_task_state(TaskState * ts)210624f7979Spbrook void init_task_state(TaskState *ts)
211624f7979Spbrook {
212eb33cdaeSCameron Esfahani     long ticks_per_sec;
213eb33cdaeSCameron Esfahani     struct timespec bt;
214eb33cdaeSCameron Esfahani 
215624f7979Spbrook     ts->used = 1;
2165bfce0b7SPeter Maydell     ts->sigaltstack_used = (struct target_sigaltstack) {
2175bfce0b7SPeter Maydell         .ss_sp = 0,
2185bfce0b7SPeter Maydell         .ss_size = 0,
2195bfce0b7SPeter Maydell         .ss_flags = TARGET_SS_DISABLE,
2205bfce0b7SPeter Maydell     };
221eb33cdaeSCameron Esfahani 
222eb33cdaeSCameron Esfahani     /* Capture task start time relative to system boot */
223eb33cdaeSCameron Esfahani 
224eb33cdaeSCameron Esfahani     ticks_per_sec = sysconf(_SC_CLK_TCK);
225eb33cdaeSCameron Esfahani 
226eb33cdaeSCameron Esfahani     if ((ticks_per_sec > 0) && !clock_gettime(CLOCK_BOOTTIME, &bt)) {
227eb33cdaeSCameron Esfahani         /* start_boottime is expressed in clock ticks */
228eb33cdaeSCameron Esfahani         ts->start_boottime = bt.tv_sec * (uint64_t) ticks_per_sec;
229eb33cdaeSCameron Esfahani         ts->start_boottime += bt.tv_nsec * (uint64_t) ticks_per_sec /
230eb33cdaeSCameron Esfahani                               NANOSECONDS_PER_SECOND;
231eb33cdaeSCameron Esfahani     }
232624f7979Spbrook }
2339de5e440Sbellard 
cpu_copy(CPUArchState * env)23430ba0ee5SAndreas Färber CPUArchState *cpu_copy(CPUArchState *env)
23530ba0ee5SAndreas Färber {
23629a0af61SRichard Henderson     CPUState *cpu = env_cpu(env);
2372278b939SIgor Mammedov     CPUState *new_cpu = cpu_create(cpu_type);
238b77af26eSRichard Henderson     CPUArchState *new_env = cpu_env(new_cpu);
23930ba0ee5SAndreas Färber     CPUBreakpoint *bp;
24030ba0ee5SAndreas Färber 
24130ba0ee5SAndreas Färber     /* Reset non arch specific state */
24275a34036SAndreas Färber     cpu_reset(new_cpu);
24330ba0ee5SAndreas Färber 
2446cc9d67cSRichard Henderson     new_cpu->tcg_cflags = cpu->tcg_cflags;
24530ba0ee5SAndreas Färber     memcpy(new_env, env, sizeof(CPUArchState));
2462732c739Sfanwj@mail.ustc.edu.cn #if defined(TARGET_I386) || defined(TARGET_X86_64)
2472732c739Sfanwj@mail.ustc.edu.cn     new_env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
2482732c739Sfanwj@mail.ustc.edu.cn                                     PROT_READ | PROT_WRITE,
2492732c739Sfanwj@mail.ustc.edu.cn                                     MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2502732c739Sfanwj@mail.ustc.edu.cn     memcpy(g2h_untagged(new_env->gdt.base), g2h_untagged(env->gdt.base),
2512732c739Sfanwj@mail.ustc.edu.cn            sizeof(uint64_t) * TARGET_GDT_ENTRIES);
2522732c739Sfanwj@mail.ustc.edu.cn     OBJECT(new_cpu)->free = OBJECT(cpu)->free;
2532732c739Sfanwj@mail.ustc.edu.cn #endif
25430ba0ee5SAndreas Färber 
25530ba0ee5SAndreas Färber     /* Clone all break/watchpoints.
25630ba0ee5SAndreas Färber        Note: Once we support ptrace with hw-debug register access, make sure
25730ba0ee5SAndreas Färber        BP_CPU break/watchpoints are handled correctly on clone. */
2581d085f6cSThierry Bultel     QTAILQ_INIT(&new_cpu->breakpoints);
259f0c3c505SAndreas Färber     QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
260b3310ab3SAndreas Färber         cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
26130ba0ee5SAndreas Färber     }
26230ba0ee5SAndreas Färber 
26330ba0ee5SAndreas Färber     return new_env;
26430ba0ee5SAndreas Färber }
26530ba0ee5SAndreas Färber 
handle_arg_help(const char * arg)266fc9c5412SJohannes Schauer static void handle_arg_help(const char *arg)
267fc9c5412SJohannes Schauer {
2684d1275c2SRiku Voipio     usage(EXIT_SUCCESS);
269fc9c5412SJohannes Schauer }
270fc9c5412SJohannes Schauer 
handle_arg_log(const char * arg)271fc9c5412SJohannes Schauer static void handle_arg_log(const char *arg)
272fc9c5412SJohannes Schauer {
2734b25a506SJosh Kunz     last_log_mask = qemu_str_to_log_mask(arg);
2744b25a506SJosh Kunz     if (!last_log_mask) {
27559a6fa6eSPeter Maydell         qemu_print_log_usage(stdout);
2764d1275c2SRiku Voipio         exit(EXIT_FAILURE);
277fc9c5412SJohannes Schauer     }
278fc9c5412SJohannes Schauer }
279fc9c5412SJohannes Schauer 
handle_arg_dfilter(const char * arg)2808423fa90SAlex Bennée static void handle_arg_dfilter(const char *arg)
2818423fa90SAlex Bennée {
2827f4341e8SAlex Bennée     qemu_set_dfilter_ranges(arg, &error_fatal);
2838423fa90SAlex Bennée }
2848423fa90SAlex Bennée 
handle_arg_log_filename(const char * arg)28550171d42S陳韋任 static void handle_arg_log_filename(const char *arg)
28650171d42S陳韋任 {
287b410253fSRichard Henderson     last_log_filename = arg;
28850171d42S陳韋任 }
28950171d42S陳韋任 
handle_arg_set_env(const char * arg)290fc9c5412SJohannes Schauer static void handle_arg_set_env(const char *arg)
291fc9c5412SJohannes Schauer {
292fc9c5412SJohannes Schauer     char *r, *p, *token;
293fc9c5412SJohannes Schauer     r = p = strdup(arg);
294fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
295fc9c5412SJohannes Schauer         if (envlist_setenv(envlist, token) != 0) {
2964d1275c2SRiku Voipio             usage(EXIT_FAILURE);
297fc9c5412SJohannes Schauer         }
298fc9c5412SJohannes Schauer     }
299fc9c5412SJohannes Schauer     free(r);
300fc9c5412SJohannes Schauer }
301fc9c5412SJohannes Schauer 
handle_arg_unset_env(const char * arg)302fc9c5412SJohannes Schauer static void handle_arg_unset_env(const char *arg)
303fc9c5412SJohannes Schauer {
304fc9c5412SJohannes Schauer     char *r, *p, *token;
305fc9c5412SJohannes Schauer     r = p = strdup(arg);
306fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
307fc9c5412SJohannes Schauer         if (envlist_unsetenv(envlist, token) != 0) {
3084d1275c2SRiku Voipio             usage(EXIT_FAILURE);
309fc9c5412SJohannes Schauer         }
310fc9c5412SJohannes Schauer     }
311fc9c5412SJohannes Schauer     free(r);
312fc9c5412SJohannes Schauer }
313fc9c5412SJohannes Schauer 
handle_arg_argv0(const char * arg)314fc9c5412SJohannes Schauer static void handle_arg_argv0(const char *arg)
315fc9c5412SJohannes Schauer {
316fc9c5412SJohannes Schauer     argv0 = strdup(arg);
317fc9c5412SJohannes Schauer }
318fc9c5412SJohannes Schauer 
handle_arg_stack_size(const char * arg)319fc9c5412SJohannes Schauer static void handle_arg_stack_size(const char *arg)
320fc9c5412SJohannes Schauer {
321fc9c5412SJohannes Schauer     char *p;
322fc9c5412SJohannes Schauer     guest_stack_size = strtoul(arg, &p, 0);
323fc9c5412SJohannes Schauer     if (guest_stack_size == 0) {
3244d1275c2SRiku Voipio         usage(EXIT_FAILURE);
325fc9c5412SJohannes Schauer     }
326fc9c5412SJohannes Schauer 
327fc9c5412SJohannes Schauer     if (*p == 'M') {
328b52713c1SPhilippe Mathieu-Daudé         guest_stack_size *= MiB;
329fc9c5412SJohannes Schauer     } else if (*p == 'k' || *p == 'K') {
330b52713c1SPhilippe Mathieu-Daudé         guest_stack_size *= KiB;
331fc9c5412SJohannes Schauer     }
332fc9c5412SJohannes Schauer }
333fc9c5412SJohannes Schauer 
handle_arg_ld_prefix(const char * arg)334fc9c5412SJohannes Schauer static void handle_arg_ld_prefix(const char *arg)
335fc9c5412SJohannes Schauer {
336fc9c5412SJohannes Schauer     interp_prefix = strdup(arg);
337fc9c5412SJohannes Schauer }
338fc9c5412SJohannes Schauer 
handle_arg_pagesize(const char * arg)339fc9c5412SJohannes Schauer static void handle_arg_pagesize(const char *arg)
340fc9c5412SJohannes Schauer {
34101e44980SRichard Henderson     unsigned size, want = qemu_real_host_page_size();
34201e44980SRichard Henderson 
34301e44980SRichard Henderson     if (qemu_strtoui(arg, NULL, 10, &size) || size != want) {
34401e44980SRichard Henderson         warn_report("Deprecated page size option cannot "
34501e44980SRichard Henderson                     "change host page size (%u)", want);
346fc9c5412SJohannes Schauer     }
347fc9c5412SJohannes Schauer }
348fc9c5412SJohannes Schauer 
handle_arg_seed(const char * arg)3495ebdd774SRichard Henderson static void handle_arg_seed(const char *arg)
350c5e4a5a9SMagnus Reftel {
3515ebdd774SRichard Henderson     seed_optarg = arg;
352c5e4a5a9SMagnus Reftel }
353c5e4a5a9SMagnus Reftel 
handle_arg_gdb(const char * arg)354fc9c5412SJohannes Schauer static void handle_arg_gdb(const char *arg)
355fc9c5412SJohannes Schauer {
356fcedd920SAlex Bennée     gdbstub = g_strdup(arg);
357fc9c5412SJohannes Schauer }
358fc9c5412SJohannes Schauer 
handle_arg_uname(const char * arg)359fc9c5412SJohannes Schauer static void handle_arg_uname(const char *arg)
360fc9c5412SJohannes Schauer {
361fc9c5412SJohannes Schauer     qemu_uname_release = strdup(arg);
362fc9c5412SJohannes Schauer }
363fc9c5412SJohannes Schauer 
handle_arg_cpu(const char * arg)364fc9c5412SJohannes Schauer static void handle_arg_cpu(const char *arg)
365fc9c5412SJohannes Schauer {
366fc9c5412SJohannes Schauer     cpu_model = strdup(arg);
367c8057f95SPeter Maydell     if (cpu_model == NULL || is_help_option(cpu_model)) {
368b67e5cb4SThomas Huth         list_cpus();
3694d1275c2SRiku Voipio         exit(EXIT_FAILURE);
370fc9c5412SJohannes Schauer     }
371fc9c5412SJohannes Schauer }
372fc9c5412SJohannes Schauer 
handle_arg_guest_base(const char * arg)373fc9c5412SJohannes Schauer static void handle_arg_guest_base(const char *arg)
374fc9c5412SJohannes Schauer {
375fc9c5412SJohannes Schauer     guest_base = strtol(arg, NULL, 0);
376e307c192SRichard Henderson     have_guest_base = true;
377fc9c5412SJohannes Schauer }
378fc9c5412SJohannes Schauer 
handle_arg_reserved_va(const char * arg)379fc9c5412SJohannes Schauer static void handle_arg_reserved_va(const char *arg)
380fc9c5412SJohannes Schauer {
381fc9c5412SJohannes Schauer     char *p;
382fc9c5412SJohannes Schauer     int shift = 0;
38395059f9cSRichard Henderson     unsigned long val;
38495059f9cSRichard Henderson 
38595059f9cSRichard Henderson     val = strtoul(arg, &p, 0);
386fc9c5412SJohannes Schauer     switch (*p) {
387fc9c5412SJohannes Schauer     case 'k':
388fc9c5412SJohannes Schauer     case 'K':
389fc9c5412SJohannes Schauer         shift = 10;
390fc9c5412SJohannes Schauer         break;
391fc9c5412SJohannes Schauer     case 'M':
392fc9c5412SJohannes Schauer         shift = 20;
393fc9c5412SJohannes Schauer         break;
394fc9c5412SJohannes Schauer     case 'G':
395fc9c5412SJohannes Schauer         shift = 30;
396fc9c5412SJohannes Schauer         break;
397fc9c5412SJohannes Schauer     }
398fc9c5412SJohannes Schauer     if (shift) {
39995059f9cSRichard Henderson         unsigned long unshifted = val;
400fc9c5412SJohannes Schauer         p++;
40195059f9cSRichard Henderson         val <<= shift;
40295059f9cSRichard Henderson         if (val >> shift != unshifted) {
403fc9c5412SJohannes Schauer             fprintf(stderr, "Reserved virtual address too big\n");
4044d1275c2SRiku Voipio             exit(EXIT_FAILURE);
405fc9c5412SJohannes Schauer         }
406fc9c5412SJohannes Schauer     }
407fc9c5412SJohannes Schauer     if (*p) {
408fc9c5412SJohannes Schauer         fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
4094d1275c2SRiku Voipio         exit(EXIT_FAILURE);
410fc9c5412SJohannes Schauer     }
41195059f9cSRichard Henderson     /* The representation is size - 1, with 0 remaining "default". */
41295059f9cSRichard Henderson     reserved_va = val ? val - 1 : 0;
413fc9c5412SJohannes Schauer }
414fc9c5412SJohannes Schauer 
415*c107521eSIlya Leoshkevich static const char *rtsig_map = CONFIG_QEMU_RTSIG_MAP;
416*c107521eSIlya Leoshkevich 
handle_arg_rtsig_map(const char * arg)417*c107521eSIlya Leoshkevich static void handle_arg_rtsig_map(const char *arg)
418*c107521eSIlya Leoshkevich {
419*c107521eSIlya Leoshkevich     rtsig_map = arg;
420*c107521eSIlya Leoshkevich }
421*c107521eSIlya Leoshkevich 
handle_arg_one_insn_per_tb(const char * arg)422e99c1f89SPeter Maydell static void handle_arg_one_insn_per_tb(const char *arg)
423fc9c5412SJohannes Schauer {
4243cfb0456SPeter Maydell     opt_one_insn_per_tb = true;
425fc9c5412SJohannes Schauer }
426fc9c5412SJohannes Schauer 
handle_arg_strace(const char * arg)427fc9c5412SJohannes Schauer static void handle_arg_strace(const char *arg)
428fc9c5412SJohannes Schauer {
4294b25a506SJosh Kunz     enable_strace = true;
430fc9c5412SJohannes Schauer }
431fc9c5412SJohannes Schauer 
handle_arg_version(const char * arg)432fc9c5412SJohannes Schauer static void handle_arg_version(const char *arg)
433fc9c5412SJohannes Schauer {
4347e563bfbSThomas Huth     printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
4350781dd6eSThomas Huth            "\n" QEMU_COPYRIGHT "\n");
4364d1275c2SRiku Voipio     exit(EXIT_SUCCESS);
437fc9c5412SJohannes Schauer }
438fc9c5412SJohannes Schauer 
handle_arg_trace(const char * arg)4396533dd6eSLluís Vilanova static void handle_arg_trace(const char *arg)
4406533dd6eSLluís Vilanova {
44192eecfffSPaolo Bonzini     trace_opt_parse(arg);
4426533dd6eSLluís Vilanova }
4436533dd6eSLluís Vilanova 
444130ea832SMax Filippov #if defined(TARGET_XTENSA)
handle_arg_abi_call0(const char * arg)445130ea832SMax Filippov static void handle_arg_abi_call0(const char *arg)
446130ea832SMax Filippov {
447130ea832SMax Filippov     xtensa_set_abi_call0();
448130ea832SMax Filippov }
449130ea832SMax Filippov #endif
450130ea832SMax Filippov 
handle_arg_perfmap(const char * arg)4515584e2dbSIlya Leoshkevich static void handle_arg_perfmap(const char *arg)
4525584e2dbSIlya Leoshkevich {
4535584e2dbSIlya Leoshkevich     perf_enable_perfmap();
4545584e2dbSIlya Leoshkevich }
4555584e2dbSIlya Leoshkevich 
handle_arg_jitdump(const char * arg)4565584e2dbSIlya Leoshkevich static void handle_arg_jitdump(const char *arg)
4575584e2dbSIlya Leoshkevich {
4585584e2dbSIlya Leoshkevich     perf_enable_jitdump();
4595584e2dbSIlya Leoshkevich }
4605584e2dbSIlya Leoshkevich 
461f308f64eSLluís Vilanova static QemuPluginList plugins = QTAILQ_HEAD_INITIALIZER(plugins);
462f308f64eSLluís Vilanova 
463f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
handle_arg_plugin(const char * arg)464f308f64eSLluís Vilanova static void handle_arg_plugin(const char *arg)
465f308f64eSLluís Vilanova {
466f308f64eSLluís Vilanova     qemu_plugin_opt_parse(arg, &plugins);
467f308f64eSLluís Vilanova }
468f308f64eSLluís Vilanova #endif
469f308f64eSLluís Vilanova 
470fc9c5412SJohannes Schauer struct qemu_argument {
471fc9c5412SJohannes Schauer     const char *argv;
472fc9c5412SJohannes Schauer     const char *env;
473fc9c5412SJohannes Schauer     bool has_arg;
474fc9c5412SJohannes Schauer     void (*handle_opt)(const char *arg);
475fc9c5412SJohannes Schauer     const char *example;
476fc9c5412SJohannes Schauer     const char *help;
477fc9c5412SJohannes Schauer };
478fc9c5412SJohannes Schauer 
47942644ceeSJim Meyering static const struct qemu_argument arg_table[] = {
480fc9c5412SJohannes Schauer     {"h",          "",                 false, handle_arg_help,
481fc9c5412SJohannes Schauer      "",           "print this help"},
482daaf8c8eSMeador Inge     {"help",       "",                 false, handle_arg_help,
483daaf8c8eSMeador Inge      "",           ""},
484fc9c5412SJohannes Schauer     {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
485fc9c5412SJohannes Schauer      "port",       "wait gdb connection to 'port'"},
486fc9c5412SJohannes Schauer     {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
487fc9c5412SJohannes Schauer      "path",       "set the elf interpreter prefix to 'path'"},
488fc9c5412SJohannes Schauer     {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
489fc9c5412SJohannes Schauer      "size",       "set the stack size to 'size' bytes"},
490fc9c5412SJohannes Schauer     {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
491c8057f95SPeter Maydell      "model",      "select CPU (-cpu help for list)"},
492fc9c5412SJohannes Schauer     {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
493fc9c5412SJohannes Schauer      "var=value",  "sets targets environment variable (see below)"},
494fc9c5412SJohannes Schauer     {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
495fc9c5412SJohannes Schauer      "var",        "unsets targets environment variable (see below)"},
496fc9c5412SJohannes Schauer     {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
497fc9c5412SJohannes Schauer      "argv0",      "forces target process argv[0] to be 'argv0'"},
498fc9c5412SJohannes Schauer     {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
499fc9c5412SJohannes Schauer      "uname",      "set qemu uname release string to 'uname'"},
500fc9c5412SJohannes Schauer     {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
501fc9c5412SJohannes Schauer      "address",    "set guest_base address to 'address'"},
502fc9c5412SJohannes Schauer     {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
503fc9c5412SJohannes Schauer      "size",       "reserve 'size' bytes for guest virtual address space"},
504*c107521eSIlya Leoshkevich     {"t",          "QEMU_RTSIG_MAP",   true,  handle_arg_rtsig_map,
505*c107521eSIlya Leoshkevich      "tsig hsig n[,...]",
506*c107521eSIlya Leoshkevich                    "map target rt signals [tsig,tsig+n) to [hsig,hsig+n]"},
507fc9c5412SJohannes Schauer     {"d",          "QEMU_LOG",         true,  handle_arg_log,
508989b697dSPeter Maydell      "item[,...]", "enable logging of specified items "
509989b697dSPeter Maydell      "(use '-d help' for a list of items)"},
5108423fa90SAlex Bennée     {"dfilter",    "QEMU_DFILTER",     true,  handle_arg_dfilter,
5118423fa90SAlex Bennée      "range[,...]","filter logging based on address range"},
51250171d42S陳韋任     {"D",          "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
513989b697dSPeter Maydell      "logfile",     "write logs to 'logfile' (default stderr)"},
514fc9c5412SJohannes Schauer     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
51501e44980SRichard Henderson      "pagesize",   "deprecated change to host page size"},
516e99c1f89SPeter Maydell     {"one-insn-per-tb",
517e99c1f89SPeter Maydell                    "QEMU_ONE_INSN_PER_TB",  false, handle_arg_one_insn_per_tb,
518e99c1f89SPeter Maydell      "",           "run with one guest instruction per emulated TB"},
519fc9c5412SJohannes Schauer     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
520fc9c5412SJohannes Schauer      "",           "log system calls"},
5215ebdd774SRichard Henderson     {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_seed,
522c5e4a5a9SMagnus Reftel      "",           "Seed for pseudo-random number generator"},
5236533dd6eSLluís Vilanova     {"trace",      "QEMU_TRACE",       true,  handle_arg_trace,
5246533dd6eSLluís Vilanova      "",           "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
525f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
526f308f64eSLluís Vilanova     {"plugin",     "QEMU_PLUGIN",      true,  handle_arg_plugin,
5273a445acbSMahmoud Mandour      "",           "[file=]<file>[,<argname>=<argvalue>]"},
528f308f64eSLluís Vilanova #endif
529fc9c5412SJohannes Schauer     {"version",    "QEMU_VERSION",     false, handle_arg_version,
5301386d4c0SPeter Maydell      "",           "display version information and exit"},
531130ea832SMax Filippov #if defined(TARGET_XTENSA)
532130ea832SMax Filippov     {"xtensa-abi-call0", "QEMU_XTENSA_ABI_CALL0", false, handle_arg_abi_call0,
533130ea832SMax Filippov      "",           "assume CALL0 Xtensa ABI"},
534130ea832SMax Filippov #endif
5355584e2dbSIlya Leoshkevich     {"perfmap",    "QEMU_PERFMAP",     false, handle_arg_perfmap,
5365584e2dbSIlya Leoshkevich      "",           "Generate a /tmp/perf-${pid}.map file for perf"},
5375584e2dbSIlya Leoshkevich     {"jitdump",    "QEMU_JITDUMP",     false, handle_arg_jitdump,
5385584e2dbSIlya Leoshkevich      "",           "Generate a jit-${pid}.dump file for perf"},
539fc9c5412SJohannes Schauer     {NULL, NULL, false, NULL, NULL, NULL}
540fc9c5412SJohannes Schauer };
541fc9c5412SJohannes Schauer 
usage(int exitcode)542d03f9c32SMeador Inge static void usage(int exitcode)
543fc9c5412SJohannes Schauer {
54442644ceeSJim Meyering     const struct qemu_argument *arginfo;
545fc9c5412SJohannes Schauer     int maxarglen;
546fc9c5412SJohannes Schauer     int maxenvlen;
547fc9c5412SJohannes Schauer 
5482e59915dSPaolo Bonzini     printf("usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
5492e59915dSPaolo Bonzini            "Linux CPU emulator (compiled for " TARGET_NAME " emulation)\n"
550fc9c5412SJohannes Schauer            "\n"
551fc9c5412SJohannes Schauer            "Options and associated environment variables:\n"
552fc9c5412SJohannes Schauer            "\n");
553fc9c5412SJohannes Schauer 
55463ec54d7SPeter Maydell     /* Calculate column widths. We must always have at least enough space
55563ec54d7SPeter Maydell      * for the column header.
55663ec54d7SPeter Maydell      */
55763ec54d7SPeter Maydell     maxarglen = strlen("Argument");
55863ec54d7SPeter Maydell     maxenvlen = strlen("Env-variable");
559fc9c5412SJohannes Schauer 
560fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
56163ec54d7SPeter Maydell         int arglen = strlen(arginfo->argv);
56263ec54d7SPeter Maydell         if (arginfo->has_arg) {
56363ec54d7SPeter Maydell             arglen += strlen(arginfo->example) + 1;
56463ec54d7SPeter Maydell         }
565fc9c5412SJohannes Schauer         if (strlen(arginfo->env) > maxenvlen) {
566fc9c5412SJohannes Schauer             maxenvlen = strlen(arginfo->env);
567fc9c5412SJohannes Schauer         }
56863ec54d7SPeter Maydell         if (arglen > maxarglen) {
56963ec54d7SPeter Maydell             maxarglen = arglen;
570fc9c5412SJohannes Schauer         }
571fc9c5412SJohannes Schauer     }
572fc9c5412SJohannes Schauer 
57363ec54d7SPeter Maydell     printf("%-*s %-*s Description\n", maxarglen+1, "Argument",
57463ec54d7SPeter Maydell             maxenvlen, "Env-variable");
575fc9c5412SJohannes Schauer 
576fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
577fc9c5412SJohannes Schauer         if (arginfo->has_arg) {
578fc9c5412SJohannes Schauer             printf("-%s %-*s %-*s %s\n", arginfo->argv,
57963ec54d7SPeter Maydell                    (int)(maxarglen - strlen(arginfo->argv) - 1),
58063ec54d7SPeter Maydell                    arginfo->example, maxenvlen, arginfo->env, arginfo->help);
581fc9c5412SJohannes Schauer         } else {
58263ec54d7SPeter Maydell             printf("-%-*s %-*s %s\n", maxarglen, arginfo->argv,
583fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env,
584fc9c5412SJohannes Schauer                     arginfo->help);
585fc9c5412SJohannes Schauer         }
586fc9c5412SJohannes Schauer     }
587fc9c5412SJohannes Schauer 
588fc9c5412SJohannes Schauer     printf("\n"
589fc9c5412SJohannes Schauer            "Defaults:\n"
590fc9c5412SJohannes Schauer            "QEMU_LD_PREFIX  = %s\n"
591989b697dSPeter Maydell            "QEMU_STACK_SIZE = %ld byte\n",
592fc9c5412SJohannes Schauer            interp_prefix,
593989b697dSPeter Maydell            guest_stack_size);
594fc9c5412SJohannes Schauer 
595fc9c5412SJohannes Schauer     printf("\n"
596fc9c5412SJohannes Schauer            "You can use -E and -U options or the QEMU_SET_ENV and\n"
597fc9c5412SJohannes Schauer            "QEMU_UNSET_ENV environment variables to set and unset\n"
598fc9c5412SJohannes Schauer            "environment variables for the target process.\n"
599fc9c5412SJohannes Schauer            "It is possible to provide several variables by separating them\n"
600fc9c5412SJohannes Schauer            "by commas in getsubopt(3) style. Additionally it is possible to\n"
601fc9c5412SJohannes Schauer            "provide the -E and -U options multiple times.\n"
602fc9c5412SJohannes Schauer            "The following lines are equivalent:\n"
603fc9c5412SJohannes Schauer            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
604fc9c5412SJohannes Schauer            "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
605fc9c5412SJohannes Schauer            "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
606fc9c5412SJohannes Schauer            "Note that if you provide several changes to a single variable\n"
607f5048cb7SEric Blake            "the last change will stay in effect.\n"
608f5048cb7SEric Blake            "\n"
609f5048cb7SEric Blake            QEMU_HELP_BOTTOM "\n");
610fc9c5412SJohannes Schauer 
611d03f9c32SMeador Inge     exit(exitcode);
612fc9c5412SJohannes Schauer }
613fc9c5412SJohannes Schauer 
parse_args(int argc,char ** argv)614fc9c5412SJohannes Schauer static int parse_args(int argc, char **argv)
615fc9c5412SJohannes Schauer {
616fc9c5412SJohannes Schauer     const char *r;
617fc9c5412SJohannes Schauer     int optind;
61842644ceeSJim Meyering     const struct qemu_argument *arginfo;
619fc9c5412SJohannes Schauer 
620fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
621fc9c5412SJohannes Schauer         if (arginfo->env == NULL) {
622fc9c5412SJohannes Schauer             continue;
623fc9c5412SJohannes Schauer         }
624fc9c5412SJohannes Schauer 
625fc9c5412SJohannes Schauer         r = getenv(arginfo->env);
626fc9c5412SJohannes Schauer         if (r != NULL) {
627fc9c5412SJohannes Schauer             arginfo->handle_opt(r);
628fc9c5412SJohannes Schauer         }
629fc9c5412SJohannes Schauer     }
630fc9c5412SJohannes Schauer 
631fc9c5412SJohannes Schauer     optind = 1;
632fc9c5412SJohannes Schauer     for (;;) {
633fc9c5412SJohannes Schauer         if (optind >= argc) {
634fc9c5412SJohannes Schauer             break;
635fc9c5412SJohannes Schauer         }
636fc9c5412SJohannes Schauer         r = argv[optind];
637fc9c5412SJohannes Schauer         if (r[0] != '-') {
638fc9c5412SJohannes Schauer             break;
639fc9c5412SJohannes Schauer         }
640fc9c5412SJohannes Schauer         optind++;
641fc9c5412SJohannes Schauer         r++;
642fc9c5412SJohannes Schauer         if (!strcmp(r, "-")) {
643fc9c5412SJohannes Schauer             break;
644fc9c5412SJohannes Schauer         }
645ba02577cSMeador Inge         /* Treat --foo the same as -foo.  */
646ba02577cSMeador Inge         if (r[0] == '-') {
647ba02577cSMeador Inge             r++;
648ba02577cSMeador Inge         }
649fc9c5412SJohannes Schauer 
650fc9c5412SJohannes Schauer         for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
651fc9c5412SJohannes Schauer             if (!strcmp(r, arginfo->argv)) {
6521386d4c0SPeter Maydell                 if (arginfo->has_arg) {
653fc9c5412SJohannes Schauer                     if (optind >= argc) {
654138940bfSMeador Inge                         (void) fprintf(stderr,
655138940bfSMeador Inge                             "qemu: missing argument for option '%s'\n", r);
6564d1275c2SRiku Voipio                         exit(EXIT_FAILURE);
657fc9c5412SJohannes Schauer                     }
658fc9c5412SJohannes Schauer                     arginfo->handle_opt(argv[optind]);
659fc9c5412SJohannes Schauer                     optind++;
6601386d4c0SPeter Maydell                 } else {
6611386d4c0SPeter Maydell                     arginfo->handle_opt(NULL);
662fc9c5412SJohannes Schauer                 }
663fc9c5412SJohannes Schauer                 break;
664fc9c5412SJohannes Schauer             }
665fc9c5412SJohannes Schauer         }
666fc9c5412SJohannes Schauer 
667fc9c5412SJohannes Schauer         /* no option matched the current argv */
668fc9c5412SJohannes Schauer         if (arginfo->handle_opt == NULL) {
669138940bfSMeador Inge             (void) fprintf(stderr, "qemu: unknown option '%s'\n", r);
6704d1275c2SRiku Voipio             exit(EXIT_FAILURE);
671fc9c5412SJohannes Schauer         }
672fc9c5412SJohannes Schauer     }
673fc9c5412SJohannes Schauer 
674fc9c5412SJohannes Schauer     if (optind >= argc) {
675138940bfSMeador Inge         (void) fprintf(stderr, "qemu: no user program specified\n");
6764d1275c2SRiku Voipio         exit(EXIT_FAILURE);
677fc9c5412SJohannes Schauer     }
678fc9c5412SJohannes Schauer 
679fc9c5412SJohannes Schauer     exec_path = argv[optind];
680fc9c5412SJohannes Schauer 
681fc9c5412SJohannes Schauer     return optind;
682fc9c5412SJohannes Schauer }
683fc9c5412SJohannes Schauer 
main(int argc,char ** argv,char ** envp)684902b3d5cSmalc int main(int argc, char **argv, char **envp)
68531e31b8aSbellard {
68601ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
68731e31b8aSbellard     struct image_info info1, *info = &info1;
688edf8e2afSMika Westerberg     struct linux_binprm bprm;
68948e15fc2SNathan Froyd     TaskState *ts;
6909349b4f9SAndreas Färber     CPUArchState *env;
691db6b81d4SAndreas Färber     CPUState *cpu;
692586314f2Sbellard     int optind;
69304a6dfebSaurel32     char **target_environ, **wrk;
6947d8cec95Saurel32     char **target_argv;
6957d8cec95Saurel32     int target_argc;
6967d8cec95Saurel32     int i;
697fd4d81ddSArnaud Patard     int ret;
69803cfd8faSLaurent Vivier     int execfd;
699ff8a8bbcSRichard Henderson     int host_page_size;
7008f67b9c6SRichard Henderson     unsigned long max_reserved_va;
7016e1c0d7bSLaurent Vivier     bool preserve_argv0;
70231e31b8aSbellard 
703f5852efaSChristophe Fergeau     error_init(argv[0]);
704fe4db84dSDaniel P. Berrange     module_call_init(MODULE_INIT_TRACE);
705267f685bSPaolo Bonzini     qemu_init_cpu_list();
706ce008c1fSAndreas Färber     module_call_init(MODULE_INIT_QOM);
707ce008c1fSAndreas Färber 
708ec45bbe5SSaurav Sachidanand     envlist = envlist_create();
70904a6dfebSaurel32 
7107f750efcSAndreas Schwab     /*
7117f750efcSAndreas Schwab      * add current environment into the list
7127f750efcSAndreas Schwab      * envlist_setenv adds to the front of the list; to preserve environ
7137f750efcSAndreas Schwab      * order add from back to front
7147f750efcSAndreas Schwab      */
71504a6dfebSaurel32     for (wrk = environ; *wrk != NULL; wrk++) {
7167f750efcSAndreas Schwab         continue;
7177f750efcSAndreas Schwab     }
7187f750efcSAndreas Schwab     while (wrk != environ) {
7197f750efcSAndreas Schwab         wrk--;
72004a6dfebSaurel32         (void) envlist_setenv(envlist, *wrk);
72104a6dfebSaurel32     }
72204a6dfebSaurel32 
723703e0e89SRichard Henderson     /* Read the stack limit from the kernel.  If it's "unlimited",
724703e0e89SRichard Henderson        then we can do little else besides use the default.  */
725703e0e89SRichard Henderson     {
726703e0e89SRichard Henderson         struct rlimit lim;
727703e0e89SRichard Henderson         if (getrlimit(RLIMIT_STACK, &lim) == 0
72881bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur != RLIM_INFINITY
7290a3346b5SHelge Deller             && lim.rlim_cur == (target_long)lim.rlim_cur
7300a3346b5SHelge Deller             && lim.rlim_cur > guest_stack_size) {
731703e0e89SRichard Henderson             guest_stack_size = lim.rlim_cur;
732703e0e89SRichard Henderson         }
733703e0e89SRichard Henderson     }
734703e0e89SRichard Henderson 
735b1f9be31Sj_mayer     cpu_model = NULL;
736b5ec5ce0Sjohn cooper 
7376533dd6eSLluís Vilanova     qemu_add_opts(&qemu_trace_opts);
738f308f64eSLluís Vilanova     qemu_plugin_add_opts();
7396533dd6eSLluís Vilanova 
740fc9c5412SJohannes Schauer     optind = parse_args(argc, argv);
7414b5dfd82SPeter Maydell 
742b410253fSRichard Henderson     qemu_set_log_filename_flags(last_log_filename,
743b410253fSRichard Henderson                                 last_log_mask | (enable_strace * LOG_STRACE),
744b410253fSRichard Henderson                                 &error_fatal);
7454b25a506SJosh Kunz 
7466533dd6eSLluís Vilanova     if (!trace_init_backends()) {
7476533dd6eSLluís Vilanova         exit(1);
7486533dd6eSLluís Vilanova     }
74992eecfffSPaolo Bonzini     trace_init_file();
7500572f558SPaolo Bonzini     qemu_plugin_load_list(&plugins, &error_fatal);
7516533dd6eSLluís Vilanova 
75231e31b8aSbellard     /* Zero out regs */
75301ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
75431e31b8aSbellard 
75531e31b8aSbellard     /* Zero out image_info */
75631e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
75731e31b8aSbellard 
758edf8e2afSMika Westerberg     memset(&bprm, 0, sizeof (bprm));
759edf8e2afSMika Westerberg 
76074cd30b8Sbellard     /* Scan interp_prefix dir for replacement files. */
76174cd30b8Sbellard     init_paths(interp_prefix);
76274cd30b8Sbellard 
7634a24a758SPeter Maydell     init_qemu_uname_release();
7644a24a758SPeter Maydell 
7656e1c0d7bSLaurent Vivier     /*
7666e1c0d7bSLaurent Vivier      * Manage binfmt-misc open-binary flag
7676e1c0d7bSLaurent Vivier      */
76825268a18SVivian Wang     errno = 0;
769768fe76eSYunQiang Su     execfd = qemu_getauxval(AT_EXECFD);
77025268a18SVivian Wang     if (errno != 0) {
7719d3019bcSLaurent Vivier         execfd = open(exec_path, O_RDONLY);
772768fe76eSYunQiang Su         if (execfd < 0) {
7739d3019bcSLaurent Vivier             printf("Error while loading %s: %s\n", exec_path, strerror(errno));
774768fe76eSYunQiang Su             _exit(EXIT_FAILURE);
775768fe76eSYunQiang Su         }
776768fe76eSYunQiang Su     }
777768fe76eSYunQiang Su 
778258bec39SHelge Deller     /* Resolve executable file name to full path name */
779258bec39SHelge Deller     if (realpath(exec_path, real_exec_path)) {
780258bec39SHelge Deller         exec_path = real_exec_path;
781258bec39SHelge Deller     }
782258bec39SHelge Deller 
7836e1c0d7bSLaurent Vivier     /*
7846e1c0d7bSLaurent Vivier      * get binfmt_misc flags
7856e1c0d7bSLaurent Vivier      */
7866e1c0d7bSLaurent Vivier     preserve_argv0 = !!(qemu_getauxval(AT_FLAGS) & AT_FLAGS_PRESERVE_ARGV0);
7876e1c0d7bSLaurent Vivier 
7886e1c0d7bSLaurent Vivier     /*
7896e1c0d7bSLaurent Vivier      * Manage binfmt-misc preserve-arg[0] flag
7906e1c0d7bSLaurent Vivier      *    argv[optind]     full path to the binary
7916e1c0d7bSLaurent Vivier      *    argv[optind + 1] original argv[0]
7926e1c0d7bSLaurent Vivier      */
7936e1c0d7bSLaurent Vivier     if (optind + 1 < argc && preserve_argv0) {
7946e1c0d7bSLaurent Vivier         optind++;
7956e1c0d7bSLaurent Vivier     }
7966e1c0d7bSLaurent Vivier 
79746027c07Sbellard     if (cpu_model == NULL) {
798768fe76eSYunQiang Su         cpu_model = cpu_get_model(get_elf_eflags(execfd));
799aaed909aSbellard     }
800c1c8cfe5SEduardo Habkost     cpu_type = parse_cpu_option(cpu_model);
8012278b939SIgor Mammedov 
80213c13397SRichard Henderson     /* init tcg before creating CPUs */
803940e43aaSClaudio Fontana     {
8043cfb0456SPeter Maydell         AccelState *accel = current_accel();
8053cfb0456SPeter Maydell         AccelClass *ac = ACCEL_GET_CLASS(accel);
8062278b939SIgor Mammedov 
807b86f59c7SClaudio Fontana         accel_init_interfaces(ac);
8083cfb0456SPeter Maydell         object_property_set_bool(OBJECT(accel), "one-insn-per-tb",
8093cfb0456SPeter Maydell                                  opt_one_insn_per_tb, &error_abort);
81092242f34SClaudio Fontana         ac->init_machine(NULL);
811940e43aaSClaudio Fontana     }
812ff8a8bbcSRichard Henderson 
813ff8a8bbcSRichard Henderson     /*
814ff8a8bbcSRichard Henderson      * Finalize page size before creating CPUs.
815ff8a8bbcSRichard Henderson      * This will do nothing if !TARGET_PAGE_BITS_VARY.
816ff8a8bbcSRichard Henderson      * The most efficient setting is to match the host.
817ff8a8bbcSRichard Henderson      */
818ff8a8bbcSRichard Henderson     host_page_size = qemu_real_host_page_size();
819ff8a8bbcSRichard Henderson     set_preferred_target_page_bits(ctz32(host_page_size));
820ff8a8bbcSRichard Henderson     finalize_target_page_bits();
821ff8a8bbcSRichard Henderson 
8222278b939SIgor Mammedov     cpu = cpu_create(cpu_type);
823b77af26eSRichard Henderson     env = cpu_env(cpu);
8240ac46af3SAndreas Färber     cpu_reset(cpu);
825db6b81d4SAndreas Färber     thread_cpu = cpu;
82654936004Sbellard 
8278f67b9c6SRichard Henderson     /*
8281b6f1b2eSWarner Losh      * Reserving too much vm space via mmap can run into problems with rlimits,
8291b6f1b2eSWarner Losh      * oom due to page table creation, etc.  We will still try it, if directed
8301b6f1b2eSWarner Losh      * by the command-line option, but not by default. Unless we're running a
8311b6f1b2eSWarner Losh      * target address space of 32 or fewer bits on a host with 64 bits.
8328f67b9c6SRichard Henderson      */
8338f67b9c6SRichard Henderson     max_reserved_va = MAX_RESERVED_VA(cpu);
8348f67b9c6SRichard Henderson     if (reserved_va != 0) {
83513c13397SRichard Henderson         if ((reserved_va + 1) % host_page_size) {
83613c13397SRichard Henderson             char *s = size_to_str(host_page_size);
8372f7828b5SRichard Henderson             fprintf(stderr, "Reserved virtual address not aligned mod %s\n", s);
8382f7828b5SRichard Henderson             g_free(s);
8392f7828b5SRichard Henderson             exit(EXIT_FAILURE);
8402f7828b5SRichard Henderson         }
8418f67b9c6SRichard Henderson         if (max_reserved_va && reserved_va > max_reserved_va) {
8428f67b9c6SRichard Henderson             fprintf(stderr, "Reserved virtual address too big\n");
8438f67b9c6SRichard Henderson             exit(EXIT_FAILURE);
8448f67b9c6SRichard Henderson         }
8458f67b9c6SRichard Henderson     } else if (HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32) {
84695059f9cSRichard Henderson         /* MAX_RESERVED_VA + 1 is a large power of 2, so is aligned. */
84795059f9cSRichard Henderson         reserved_va = max_reserved_va;
8488f67b9c6SRichard Henderson     }
8498f67b9c6SRichard Henderson 
850c8fb5cf9SRichard Henderson     /*
851c8fb5cf9SRichard Henderson      * Temporarily disable
852c8fb5cf9SRichard Henderson      *   "comparison is always false due to limited range of data type"
853c8fb5cf9SRichard Henderson      * due to comparison between (possible) uint64_t and uintptr_t.
854c8fb5cf9SRichard Henderson      */
855c8fb5cf9SRichard Henderson #pragma GCC diagnostic push
856c8fb5cf9SRichard Henderson #pragma GCC diagnostic ignored "-Wtype-limits"
857f324a03eSRichard Henderson #pragma GCC diagnostic ignored "-Wtautological-compare"
858c8fb5cf9SRichard Henderson 
859c8fb5cf9SRichard Henderson     /*
860c8fb5cf9SRichard Henderson      * Select an initial value for task_unmapped_base that is in range.
861c8fb5cf9SRichard Henderson      */
862c8fb5cf9SRichard Henderson     if (reserved_va) {
863c8fb5cf9SRichard Henderson         if (TASK_UNMAPPED_BASE < reserved_va) {
864c8fb5cf9SRichard Henderson             task_unmapped_base = TASK_UNMAPPED_BASE;
865c8fb5cf9SRichard Henderson         } else {
866c8fb5cf9SRichard Henderson             /* The most common default formula is TASK_SIZE / 3. */
867c8fb5cf9SRichard Henderson             task_unmapped_base = TARGET_PAGE_ALIGN(reserved_va / 3);
868c8fb5cf9SRichard Henderson         }
869c8fb5cf9SRichard Henderson     } else if (TASK_UNMAPPED_BASE < UINTPTR_MAX) {
870c8fb5cf9SRichard Henderson         task_unmapped_base = TASK_UNMAPPED_BASE;
871c8fb5cf9SRichard Henderson     } else {
872c8fb5cf9SRichard Henderson         /* 32-bit host: pick something medium size. */
873c8fb5cf9SRichard Henderson         task_unmapped_base = 0x10000000;
874c8fb5cf9SRichard Henderson     }
875c8fb5cf9SRichard Henderson     mmap_next_start = task_unmapped_base;
876c8fb5cf9SRichard Henderson 
877da2b71faSRichard Henderson     /* Similarly for elf_et_dyn_base. */
878da2b71faSRichard Henderson     if (reserved_va) {
879da2b71faSRichard Henderson         if (ELF_ET_DYN_BASE < reserved_va) {
880da2b71faSRichard Henderson             elf_et_dyn_base = ELF_ET_DYN_BASE;
881da2b71faSRichard Henderson         } else {
882da2b71faSRichard Henderson             /* The most common default formula is TASK_SIZE / 3 * 2. */
883da2b71faSRichard Henderson             elf_et_dyn_base = TARGET_PAGE_ALIGN(reserved_va / 3) * 2;
884da2b71faSRichard Henderson         }
885da2b71faSRichard Henderson     } else if (ELF_ET_DYN_BASE < UINTPTR_MAX) {
886da2b71faSRichard Henderson         elf_et_dyn_base = ELF_ET_DYN_BASE;
887da2b71faSRichard Henderson     } else {
888da2b71faSRichard Henderson         /* 32-bit host: pick something medium size. */
889da2b71faSRichard Henderson         elf_et_dyn_base = 0x18000000;
890da2b71faSRichard Henderson     }
891da2b71faSRichard Henderson 
892c8fb5cf9SRichard Henderson #pragma GCC diagnostic pop
893c8fb5cf9SRichard Henderson 
894a573e9baSRichard Henderson     {
895a573e9baSRichard Henderson         Error *err = NULL;
8965ebdd774SRichard Henderson         if (seed_optarg != NULL) {
897a573e9baSRichard Henderson             qemu_guest_random_seed_main(seed_optarg, &err);
898a573e9baSRichard Henderson         } else {
899a573e9baSRichard Henderson             qcrypto_init(&err);
900a573e9baSRichard Henderson         }
901a573e9baSRichard Henderson         if (err) {
902a573e9baSRichard Henderson             error_reportf_err(err, "cannot initialize crypto: ");
903a573e9baSRichard Henderson             exit(1);
904a573e9baSRichard Henderson         }
905c5e4a5a9SMagnus Reftel     }
906c5e4a5a9SMagnus Reftel 
90704a6dfebSaurel32     target_environ = envlist_to_environ(envlist, NULL);
90804a6dfebSaurel32     envlist_free(envlist);
909b12b6a18Sths 
910379f6698SPaul Brook     /*
911379f6698SPaul Brook      * Read in mmap_min_addr kernel parameter.  This value is used
912379f6698SPaul Brook      * When loading the ELF image to determine whether guest_base
91314f24e14SRichard Henderson      * is needed.  It is also used in mmap_find_vma.
914379f6698SPaul Brook      */
91514f24e14SRichard Henderson     {
916379f6698SPaul Brook         FILE *fp;
917379f6698SPaul Brook 
918379f6698SPaul Brook         if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
919379f6698SPaul Brook             unsigned long tmp;
920c9f80666SRichard Henderson             if (fscanf(fp, "%lu", &tmp) == 1 && tmp != 0) {
92178b79b2cSRichard Henderson                 mmap_min_addr = MAX(tmp, host_page_size);
922c9f80666SRichard Henderson                 qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n",
923c9f80666SRichard Henderson                               mmap_min_addr);
924379f6698SPaul Brook             }
925379f6698SPaul Brook             fclose(fp);
926379f6698SPaul Brook         }
927379f6698SPaul Brook     }
928379f6698SPaul Brook 
9297d8cec95Saurel32     /*
930c9f80666SRichard Henderson      * We prefer to not make NULL pointers accessible to QEMU.
931c9f80666SRichard Henderson      * If we're in a chroot with no /proc, fall back to 1 page.
932c9f80666SRichard Henderson      */
933c9f80666SRichard Henderson     if (mmap_min_addr == 0) {
934ff8a8bbcSRichard Henderson         mmap_min_addr = host_page_size;
935c9f80666SRichard Henderson         qemu_log_mask(CPU_LOG_PAGE,
936c9f80666SRichard Henderson                       "host mmap_min_addr=0x%lx (fallback)\n",
937c9f80666SRichard Henderson                       mmap_min_addr);
938c9f80666SRichard Henderson     }
939c9f80666SRichard Henderson 
940c9f80666SRichard Henderson     /*
9417d8cec95Saurel32      * Prepare copy of argv vector for target.
9427d8cec95Saurel32      */
9437d8cec95Saurel32     target_argc = argc - optind;
9442ee80bceSNguyen Dinh Phi     target_argv = g_new0(char *, target_argc + 1);
9457d8cec95Saurel32 
9467d8cec95Saurel32     /*
9477d8cec95Saurel32      * If argv0 is specified (using '-0' switch) we replace
9487d8cec95Saurel32      * argv[0] pointer with the given one.
9497d8cec95Saurel32      */
9507d8cec95Saurel32     i = 0;
9517d8cec95Saurel32     if (argv0 != NULL) {
9527d8cec95Saurel32         target_argv[i++] = strdup(argv0);
9537d8cec95Saurel32     }
9547d8cec95Saurel32     for (; i < target_argc; i++) {
9557d8cec95Saurel32         target_argv[i] = strdup(argv[optind + i]);
9567d8cec95Saurel32     }
9577d8cec95Saurel32     target_argv[target_argc] = NULL;
9587d8cec95Saurel32 
959c78d65e8SMarkus Armbruster     ts = g_new0(TaskState, 1);
960edf8e2afSMika Westerberg     init_task_state(ts);
961edf8e2afSMika Westerberg     /* build Task State */
962edf8e2afSMika Westerberg     ts->info = info;
963edf8e2afSMika Westerberg     ts->bprm = &bprm;
9640429a971SAndreas Färber     cpu->opaque = ts;
965edf8e2afSMika Westerberg     task_settid(ts);
966edf8e2afSMika Westerberg 
967c093364fSOwen Anderson     fd_trans_init();
968c093364fSOwen Anderson 
9699d3019bcSLaurent Vivier     ret = loader_exec(execfd, exec_path, target_argv, target_environ, regs,
970fd4d81ddSArnaud Patard         info, &bprm);
971fd4d81ddSArnaud Patard     if (ret != 0) {
9729d3019bcSLaurent Vivier         printf("Error while loading %s: %s\n", exec_path, strerror(-ret));
9734d1275c2SRiku Voipio         _exit(EXIT_FAILURE);
97431e31b8aSbellard     }
97531e31b8aSbellard 
976b12b6a18Sths     for (wrk = target_environ; *wrk; wrk++) {
977ec45bbe5SSaurav Sachidanand         g_free(*wrk);
978b12b6a18Sths     }
979b12b6a18Sths 
980ec45bbe5SSaurav Sachidanand     g_free(target_environ);
981b12b6a18Sths 
98213829020SPaolo Bonzini     if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
98393756fdcSRichard Henderson         FILE *f = qemu_log_trylock();
98493756fdcSRichard Henderson         if (f) {
98593756fdcSRichard Henderson             fprintf(f, "guest_base  %p\n", (void *)guest_base);
98693756fdcSRichard Henderson             fprintf(f, "page layout changed following binary load\n");
98793756fdcSRichard Henderson             page_dump(f);
98854936004Sbellard 
98993756fdcSRichard Henderson             fprintf(f, "end_code    0x" TARGET_ABI_FMT_lx "\n",
99093756fdcSRichard Henderson                     info->end_code);
99193756fdcSRichard Henderson             fprintf(f, "start_code  0x" TARGET_ABI_FMT_lx "\n",
99293756fdcSRichard Henderson                     info->start_code);
99393756fdcSRichard Henderson             fprintf(f, "start_data  0x" TARGET_ABI_FMT_lx "\n",
99493756fdcSRichard Henderson                     info->start_data);
99593756fdcSRichard Henderson             fprintf(f, "end_data    0x" TARGET_ABI_FMT_lx "\n",
99693756fdcSRichard Henderson                     info->end_data);
99793756fdcSRichard Henderson             fprintf(f, "start_stack 0x" TARGET_ABI_FMT_lx "\n",
99893756fdcSRichard Henderson                     info->start_stack);
99993756fdcSRichard Henderson             fprintf(f, "brk         0x" TARGET_ABI_FMT_lx "\n",
100093756fdcSRichard Henderson                     info->brk);
100193756fdcSRichard Henderson             fprintf(f, "entry       0x" TARGET_ABI_FMT_lx "\n",
100293756fdcSRichard Henderson                     info->entry);
100393756fdcSRichard Henderson             fprintf(f, "argv_start  0x" TARGET_ABI_FMT_lx "\n",
100460f1c801SRichard Henderson                     info->argv);
100593756fdcSRichard Henderson             fprintf(f, "env_start   0x" TARGET_ABI_FMT_lx "\n",
100660f1c801SRichard Henderson                     info->envp);
100793756fdcSRichard Henderson             fprintf(f, "auxv_start  0x" TARGET_ABI_FMT_lx "\n",
100893756fdcSRichard Henderson                     info->saved_auxv);
100993756fdcSRichard Henderson             qemu_log_unlock(f);
101093756fdcSRichard Henderson         }
10112e77eac6Sblueswir1     }
101231e31b8aSbellard 
101353a5960aSpbrook     target_set_brk(info->brk);
101431e31b8aSbellard     syscall_init();
1015*c107521eSIlya Leoshkevich     signal_init(rtsig_map);
101631e31b8aSbellard 
10179002ec79SRichard Henderson     /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
10189002ec79SRichard Henderson        generating the prologue until now so that the prologue can take
10199002ec79SRichard Henderson        the real value of GUEST_BASE into account.  */
1020935f75aeSRichard Henderson     tcg_prologue_init();
10219002ec79SRichard Henderson 
1022cd71c089SLaurent Vivier     target_cpu_copy_regs(env, regs);
1023cd71c089SLaurent Vivier 
1024fcedd920SAlex Bennée     if (gdbstub) {
1025fcedd920SAlex Bennée         if (gdbserver_start(gdbstub) < 0) {
1026fcedd920SAlex Bennée             fprintf(stderr, "qemu: could not open gdbserver on %s\n",
1027fcedd920SAlex Bennée                     gdbstub);
10284d1275c2SRiku Voipio             exit(EXIT_FAILURE);
1029ff7a981aSPeter Maydell         }
1030f84e313eSGustavo Romero         gdb_handlesig(cpu, 0, NULL, NULL, 0);
10311fddef4bSbellard     }
1032e4a4aaa5SRichard Henderson 
1033e4a4aaa5SRichard Henderson #ifdef CONFIG_SEMIHOSTING
1034e4a4aaa5SRichard Henderson     qemu_semihosting_guestfd_init();
1035e4a4aaa5SRichard Henderson #endif
1036e4a4aaa5SRichard Henderson 
10371b6b029eSbellard     cpu_loop(env);
10381b6b029eSbellard     /* never exits */
103931e31b8aSbellard     return 0;
104031e31b8aSbellard }
1041