xref: /qemu/linux-user/main.c (revision 16aa8eaa)
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 
handle_arg_one_insn_per_tb(const char * arg)415e99c1f89SPeter Maydell static void handle_arg_one_insn_per_tb(const char *arg)
416fc9c5412SJohannes Schauer {
4173cfb0456SPeter Maydell     opt_one_insn_per_tb = true;
418fc9c5412SJohannes Schauer }
419fc9c5412SJohannes Schauer 
handle_arg_strace(const char * arg)420fc9c5412SJohannes Schauer static void handle_arg_strace(const char *arg)
421fc9c5412SJohannes Schauer {
4224b25a506SJosh Kunz     enable_strace = true;
423fc9c5412SJohannes Schauer }
424fc9c5412SJohannes Schauer 
handle_arg_version(const char * arg)425fc9c5412SJohannes Schauer static void handle_arg_version(const char *arg)
426fc9c5412SJohannes Schauer {
4277e563bfbSThomas Huth     printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
4280781dd6eSThomas Huth            "\n" QEMU_COPYRIGHT "\n");
4294d1275c2SRiku Voipio     exit(EXIT_SUCCESS);
430fc9c5412SJohannes Schauer }
431fc9c5412SJohannes Schauer 
handle_arg_trace(const char * arg)4326533dd6eSLluís Vilanova static void handle_arg_trace(const char *arg)
4336533dd6eSLluís Vilanova {
43492eecfffSPaolo Bonzini     trace_opt_parse(arg);
4356533dd6eSLluís Vilanova }
4366533dd6eSLluís Vilanova 
437130ea832SMax Filippov #if defined(TARGET_XTENSA)
handle_arg_abi_call0(const char * arg)438130ea832SMax Filippov static void handle_arg_abi_call0(const char *arg)
439130ea832SMax Filippov {
440130ea832SMax Filippov     xtensa_set_abi_call0();
441130ea832SMax Filippov }
442130ea832SMax Filippov #endif
443130ea832SMax Filippov 
handle_arg_perfmap(const char * arg)4445584e2dbSIlya Leoshkevich static void handle_arg_perfmap(const char *arg)
4455584e2dbSIlya Leoshkevich {
4465584e2dbSIlya Leoshkevich     perf_enable_perfmap();
4475584e2dbSIlya Leoshkevich }
4485584e2dbSIlya Leoshkevich 
handle_arg_jitdump(const char * arg)4495584e2dbSIlya Leoshkevich static void handle_arg_jitdump(const char *arg)
4505584e2dbSIlya Leoshkevich {
4515584e2dbSIlya Leoshkevich     perf_enable_jitdump();
4525584e2dbSIlya Leoshkevich }
4535584e2dbSIlya Leoshkevich 
454f308f64eSLluís Vilanova static QemuPluginList plugins = QTAILQ_HEAD_INITIALIZER(plugins);
455f308f64eSLluís Vilanova 
456f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
handle_arg_plugin(const char * arg)457f308f64eSLluís Vilanova static void handle_arg_plugin(const char *arg)
458f308f64eSLluís Vilanova {
459f308f64eSLluís Vilanova     qemu_plugin_opt_parse(arg, &plugins);
460f308f64eSLluís Vilanova }
461f308f64eSLluís Vilanova #endif
462f308f64eSLluís Vilanova 
463fc9c5412SJohannes Schauer struct qemu_argument {
464fc9c5412SJohannes Schauer     const char *argv;
465fc9c5412SJohannes Schauer     const char *env;
466fc9c5412SJohannes Schauer     bool has_arg;
467fc9c5412SJohannes Schauer     void (*handle_opt)(const char *arg);
468fc9c5412SJohannes Schauer     const char *example;
469fc9c5412SJohannes Schauer     const char *help;
470fc9c5412SJohannes Schauer };
471fc9c5412SJohannes Schauer 
47242644ceeSJim Meyering static const struct qemu_argument arg_table[] = {
473fc9c5412SJohannes Schauer     {"h",          "",                 false, handle_arg_help,
474fc9c5412SJohannes Schauer      "",           "print this help"},
475daaf8c8eSMeador Inge     {"help",       "",                 false, handle_arg_help,
476daaf8c8eSMeador Inge      "",           ""},
477fc9c5412SJohannes Schauer     {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
478fc9c5412SJohannes Schauer      "port",       "wait gdb connection to 'port'"},
479fc9c5412SJohannes Schauer     {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
480fc9c5412SJohannes Schauer      "path",       "set the elf interpreter prefix to 'path'"},
481fc9c5412SJohannes Schauer     {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
482fc9c5412SJohannes Schauer      "size",       "set the stack size to 'size' bytes"},
483fc9c5412SJohannes Schauer     {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
484c8057f95SPeter Maydell      "model",      "select CPU (-cpu help for list)"},
485fc9c5412SJohannes Schauer     {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
486fc9c5412SJohannes Schauer      "var=value",  "sets targets environment variable (see below)"},
487fc9c5412SJohannes Schauer     {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
488fc9c5412SJohannes Schauer      "var",        "unsets targets environment variable (see below)"},
489fc9c5412SJohannes Schauer     {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
490fc9c5412SJohannes Schauer      "argv0",      "forces target process argv[0] to be 'argv0'"},
491fc9c5412SJohannes Schauer     {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
492fc9c5412SJohannes Schauer      "uname",      "set qemu uname release string to 'uname'"},
493fc9c5412SJohannes Schauer     {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
494fc9c5412SJohannes Schauer      "address",    "set guest_base address to 'address'"},
495fc9c5412SJohannes Schauer     {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
496fc9c5412SJohannes Schauer      "size",       "reserve 'size' bytes for guest virtual address space"},
497fc9c5412SJohannes Schauer     {"d",          "QEMU_LOG",         true,  handle_arg_log,
498989b697dSPeter Maydell      "item[,...]", "enable logging of specified items "
499989b697dSPeter Maydell      "(use '-d help' for a list of items)"},
5008423fa90SAlex Bennée     {"dfilter",    "QEMU_DFILTER",     true,  handle_arg_dfilter,
5018423fa90SAlex Bennée      "range[,...]","filter logging based on address range"},
50250171d42S陳韋任     {"D",          "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
503989b697dSPeter Maydell      "logfile",     "write logs to 'logfile' (default stderr)"},
504fc9c5412SJohannes Schauer     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
50501e44980SRichard Henderson      "pagesize",   "deprecated change to host page size"},
506e99c1f89SPeter Maydell     {"one-insn-per-tb",
507e99c1f89SPeter Maydell                    "QEMU_ONE_INSN_PER_TB",  false, handle_arg_one_insn_per_tb,
508e99c1f89SPeter Maydell      "",           "run with one guest instruction per emulated TB"},
509fc9c5412SJohannes Schauer     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
510fc9c5412SJohannes Schauer      "",           "log system calls"},
5115ebdd774SRichard Henderson     {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_seed,
512c5e4a5a9SMagnus Reftel      "",           "Seed for pseudo-random number generator"},
5136533dd6eSLluís Vilanova     {"trace",      "QEMU_TRACE",       true,  handle_arg_trace,
5146533dd6eSLluís Vilanova      "",           "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
515f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
516f308f64eSLluís Vilanova     {"plugin",     "QEMU_PLUGIN",      true,  handle_arg_plugin,
5173a445acbSMahmoud Mandour      "",           "[file=]<file>[,<argname>=<argvalue>]"},
518f308f64eSLluís Vilanova #endif
519fc9c5412SJohannes Schauer     {"version",    "QEMU_VERSION",     false, handle_arg_version,
5201386d4c0SPeter Maydell      "",           "display version information and exit"},
521130ea832SMax Filippov #if defined(TARGET_XTENSA)
522130ea832SMax Filippov     {"xtensa-abi-call0", "QEMU_XTENSA_ABI_CALL0", false, handle_arg_abi_call0,
523130ea832SMax Filippov      "",           "assume CALL0 Xtensa ABI"},
524130ea832SMax Filippov #endif
5255584e2dbSIlya Leoshkevich     {"perfmap",    "QEMU_PERFMAP",     false, handle_arg_perfmap,
5265584e2dbSIlya Leoshkevich      "",           "Generate a /tmp/perf-${pid}.map file for perf"},
5275584e2dbSIlya Leoshkevich     {"jitdump",    "QEMU_JITDUMP",     false, handle_arg_jitdump,
5285584e2dbSIlya Leoshkevich      "",           "Generate a jit-${pid}.dump file for perf"},
529fc9c5412SJohannes Schauer     {NULL, NULL, false, NULL, NULL, NULL}
530fc9c5412SJohannes Schauer };
531fc9c5412SJohannes Schauer 
usage(int exitcode)532d03f9c32SMeador Inge static void usage(int exitcode)
533fc9c5412SJohannes Schauer {
53442644ceeSJim Meyering     const struct qemu_argument *arginfo;
535fc9c5412SJohannes Schauer     int maxarglen;
536fc9c5412SJohannes Schauer     int maxenvlen;
537fc9c5412SJohannes Schauer 
5382e59915dSPaolo Bonzini     printf("usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
5392e59915dSPaolo Bonzini            "Linux CPU emulator (compiled for " TARGET_NAME " emulation)\n"
540fc9c5412SJohannes Schauer            "\n"
541fc9c5412SJohannes Schauer            "Options and associated environment variables:\n"
542fc9c5412SJohannes Schauer            "\n");
543fc9c5412SJohannes Schauer 
54463ec54d7SPeter Maydell     /* Calculate column widths. We must always have at least enough space
54563ec54d7SPeter Maydell      * for the column header.
54663ec54d7SPeter Maydell      */
54763ec54d7SPeter Maydell     maxarglen = strlen("Argument");
54863ec54d7SPeter Maydell     maxenvlen = strlen("Env-variable");
549fc9c5412SJohannes Schauer 
550fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
55163ec54d7SPeter Maydell         int arglen = strlen(arginfo->argv);
55263ec54d7SPeter Maydell         if (arginfo->has_arg) {
55363ec54d7SPeter Maydell             arglen += strlen(arginfo->example) + 1;
55463ec54d7SPeter Maydell         }
555fc9c5412SJohannes Schauer         if (strlen(arginfo->env) > maxenvlen) {
556fc9c5412SJohannes Schauer             maxenvlen = strlen(arginfo->env);
557fc9c5412SJohannes Schauer         }
55863ec54d7SPeter Maydell         if (arglen > maxarglen) {
55963ec54d7SPeter Maydell             maxarglen = arglen;
560fc9c5412SJohannes Schauer         }
561fc9c5412SJohannes Schauer     }
562fc9c5412SJohannes Schauer 
56363ec54d7SPeter Maydell     printf("%-*s %-*s Description\n", maxarglen+1, "Argument",
56463ec54d7SPeter Maydell             maxenvlen, "Env-variable");
565fc9c5412SJohannes Schauer 
566fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
567fc9c5412SJohannes Schauer         if (arginfo->has_arg) {
568fc9c5412SJohannes Schauer             printf("-%s %-*s %-*s %s\n", arginfo->argv,
56963ec54d7SPeter Maydell                    (int)(maxarglen - strlen(arginfo->argv) - 1),
57063ec54d7SPeter Maydell                    arginfo->example, maxenvlen, arginfo->env, arginfo->help);
571fc9c5412SJohannes Schauer         } else {
57263ec54d7SPeter Maydell             printf("-%-*s %-*s %s\n", maxarglen, arginfo->argv,
573fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env,
574fc9c5412SJohannes Schauer                     arginfo->help);
575fc9c5412SJohannes Schauer         }
576fc9c5412SJohannes Schauer     }
577fc9c5412SJohannes Schauer 
578fc9c5412SJohannes Schauer     printf("\n"
579fc9c5412SJohannes Schauer            "Defaults:\n"
580fc9c5412SJohannes Schauer            "QEMU_LD_PREFIX  = %s\n"
581989b697dSPeter Maydell            "QEMU_STACK_SIZE = %ld byte\n",
582fc9c5412SJohannes Schauer            interp_prefix,
583989b697dSPeter Maydell            guest_stack_size);
584fc9c5412SJohannes Schauer 
585fc9c5412SJohannes Schauer     printf("\n"
586fc9c5412SJohannes Schauer            "You can use -E and -U options or the QEMU_SET_ENV and\n"
587fc9c5412SJohannes Schauer            "QEMU_UNSET_ENV environment variables to set and unset\n"
588fc9c5412SJohannes Schauer            "environment variables for the target process.\n"
589fc9c5412SJohannes Schauer            "It is possible to provide several variables by separating them\n"
590fc9c5412SJohannes Schauer            "by commas in getsubopt(3) style. Additionally it is possible to\n"
591fc9c5412SJohannes Schauer            "provide the -E and -U options multiple times.\n"
592fc9c5412SJohannes Schauer            "The following lines are equivalent:\n"
593fc9c5412SJohannes Schauer            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
594fc9c5412SJohannes Schauer            "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
595fc9c5412SJohannes Schauer            "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
596fc9c5412SJohannes Schauer            "Note that if you provide several changes to a single variable\n"
597f5048cb7SEric Blake            "the last change will stay in effect.\n"
598f5048cb7SEric Blake            "\n"
599f5048cb7SEric Blake            QEMU_HELP_BOTTOM "\n");
600fc9c5412SJohannes Schauer 
601d03f9c32SMeador Inge     exit(exitcode);
602fc9c5412SJohannes Schauer }
603fc9c5412SJohannes Schauer 
parse_args(int argc,char ** argv)604fc9c5412SJohannes Schauer static int parse_args(int argc, char **argv)
605fc9c5412SJohannes Schauer {
606fc9c5412SJohannes Schauer     const char *r;
607fc9c5412SJohannes Schauer     int optind;
60842644ceeSJim Meyering     const struct qemu_argument *arginfo;
609fc9c5412SJohannes Schauer 
610fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
611fc9c5412SJohannes Schauer         if (arginfo->env == NULL) {
612fc9c5412SJohannes Schauer             continue;
613fc9c5412SJohannes Schauer         }
614fc9c5412SJohannes Schauer 
615fc9c5412SJohannes Schauer         r = getenv(arginfo->env);
616fc9c5412SJohannes Schauer         if (r != NULL) {
617fc9c5412SJohannes Schauer             arginfo->handle_opt(r);
618fc9c5412SJohannes Schauer         }
619fc9c5412SJohannes Schauer     }
620fc9c5412SJohannes Schauer 
621fc9c5412SJohannes Schauer     optind = 1;
622fc9c5412SJohannes Schauer     for (;;) {
623fc9c5412SJohannes Schauer         if (optind >= argc) {
624fc9c5412SJohannes Schauer             break;
625fc9c5412SJohannes Schauer         }
626fc9c5412SJohannes Schauer         r = argv[optind];
627fc9c5412SJohannes Schauer         if (r[0] != '-') {
628fc9c5412SJohannes Schauer             break;
629fc9c5412SJohannes Schauer         }
630fc9c5412SJohannes Schauer         optind++;
631fc9c5412SJohannes Schauer         r++;
632fc9c5412SJohannes Schauer         if (!strcmp(r, "-")) {
633fc9c5412SJohannes Schauer             break;
634fc9c5412SJohannes Schauer         }
635ba02577cSMeador Inge         /* Treat --foo the same as -foo.  */
636ba02577cSMeador Inge         if (r[0] == '-') {
637ba02577cSMeador Inge             r++;
638ba02577cSMeador Inge         }
639fc9c5412SJohannes Schauer 
640fc9c5412SJohannes Schauer         for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
641fc9c5412SJohannes Schauer             if (!strcmp(r, arginfo->argv)) {
6421386d4c0SPeter Maydell                 if (arginfo->has_arg) {
643fc9c5412SJohannes Schauer                     if (optind >= argc) {
644138940bfSMeador Inge                         (void) fprintf(stderr,
645138940bfSMeador Inge                             "qemu: missing argument for option '%s'\n", r);
6464d1275c2SRiku Voipio                         exit(EXIT_FAILURE);
647fc9c5412SJohannes Schauer                     }
648fc9c5412SJohannes Schauer                     arginfo->handle_opt(argv[optind]);
649fc9c5412SJohannes Schauer                     optind++;
6501386d4c0SPeter Maydell                 } else {
6511386d4c0SPeter Maydell                     arginfo->handle_opt(NULL);
652fc9c5412SJohannes Schauer                 }
653fc9c5412SJohannes Schauer                 break;
654fc9c5412SJohannes Schauer             }
655fc9c5412SJohannes Schauer         }
656fc9c5412SJohannes Schauer 
657fc9c5412SJohannes Schauer         /* no option matched the current argv */
658fc9c5412SJohannes Schauer         if (arginfo->handle_opt == NULL) {
659138940bfSMeador Inge             (void) fprintf(stderr, "qemu: unknown option '%s'\n", r);
6604d1275c2SRiku Voipio             exit(EXIT_FAILURE);
661fc9c5412SJohannes Schauer         }
662fc9c5412SJohannes Schauer     }
663fc9c5412SJohannes Schauer 
664fc9c5412SJohannes Schauer     if (optind >= argc) {
665138940bfSMeador Inge         (void) fprintf(stderr, "qemu: no user program specified\n");
6664d1275c2SRiku Voipio         exit(EXIT_FAILURE);
667fc9c5412SJohannes Schauer     }
668fc9c5412SJohannes Schauer 
669fc9c5412SJohannes Schauer     exec_path = argv[optind];
670fc9c5412SJohannes Schauer 
671fc9c5412SJohannes Schauer     return optind;
672fc9c5412SJohannes Schauer }
673fc9c5412SJohannes Schauer 
main(int argc,char ** argv,char ** envp)674902b3d5cSmalc int main(int argc, char **argv, char **envp)
67531e31b8aSbellard {
67601ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
67731e31b8aSbellard     struct image_info info1, *info = &info1;
678edf8e2afSMika Westerberg     struct linux_binprm bprm;
67948e15fc2SNathan Froyd     TaskState *ts;
6809349b4f9SAndreas Färber     CPUArchState *env;
681db6b81d4SAndreas Färber     CPUState *cpu;
682586314f2Sbellard     int optind;
68304a6dfebSaurel32     char **target_environ, **wrk;
6847d8cec95Saurel32     char **target_argv;
6857d8cec95Saurel32     int target_argc;
6867d8cec95Saurel32     int i;
687fd4d81ddSArnaud Patard     int ret;
68803cfd8faSLaurent Vivier     int execfd;
689ff8a8bbcSRichard Henderson     int host_page_size;
6908f67b9c6SRichard Henderson     unsigned long max_reserved_va;
6916e1c0d7bSLaurent Vivier     bool preserve_argv0;
69231e31b8aSbellard 
693f5852efaSChristophe Fergeau     error_init(argv[0]);
694fe4db84dSDaniel P. Berrange     module_call_init(MODULE_INIT_TRACE);
695267f685bSPaolo Bonzini     qemu_init_cpu_list();
696ce008c1fSAndreas Färber     module_call_init(MODULE_INIT_QOM);
697ce008c1fSAndreas Färber 
698ec45bbe5SSaurav Sachidanand     envlist = envlist_create();
69904a6dfebSaurel32 
7007f750efcSAndreas Schwab     /*
7017f750efcSAndreas Schwab      * add current environment into the list
7027f750efcSAndreas Schwab      * envlist_setenv adds to the front of the list; to preserve environ
7037f750efcSAndreas Schwab      * order add from back to front
7047f750efcSAndreas Schwab      */
70504a6dfebSaurel32     for (wrk = environ; *wrk != NULL; wrk++) {
7067f750efcSAndreas Schwab         continue;
7077f750efcSAndreas Schwab     }
7087f750efcSAndreas Schwab     while (wrk != environ) {
7097f750efcSAndreas Schwab         wrk--;
71004a6dfebSaurel32         (void) envlist_setenv(envlist, *wrk);
71104a6dfebSaurel32     }
71204a6dfebSaurel32 
713703e0e89SRichard Henderson     /* Read the stack limit from the kernel.  If it's "unlimited",
714703e0e89SRichard Henderson        then we can do little else besides use the default.  */
715703e0e89SRichard Henderson     {
716703e0e89SRichard Henderson         struct rlimit lim;
717703e0e89SRichard Henderson         if (getrlimit(RLIMIT_STACK, &lim) == 0
71881bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur != RLIM_INFINITY
7190a3346b5SHelge Deller             && lim.rlim_cur == (target_long)lim.rlim_cur
7200a3346b5SHelge Deller             && lim.rlim_cur > guest_stack_size) {
721703e0e89SRichard Henderson             guest_stack_size = lim.rlim_cur;
722703e0e89SRichard Henderson         }
723703e0e89SRichard Henderson     }
724703e0e89SRichard Henderson 
725b1f9be31Sj_mayer     cpu_model = NULL;
726b5ec5ce0Sjohn cooper 
7276533dd6eSLluís Vilanova     qemu_add_opts(&qemu_trace_opts);
728f308f64eSLluís Vilanova     qemu_plugin_add_opts();
7296533dd6eSLluís Vilanova 
730fc9c5412SJohannes Schauer     optind = parse_args(argc, argv);
7314b5dfd82SPeter Maydell 
732b410253fSRichard Henderson     qemu_set_log_filename_flags(last_log_filename,
733b410253fSRichard Henderson                                 last_log_mask | (enable_strace * LOG_STRACE),
734b410253fSRichard Henderson                                 &error_fatal);
7354b25a506SJosh Kunz 
7366533dd6eSLluís Vilanova     if (!trace_init_backends()) {
7376533dd6eSLluís Vilanova         exit(1);
7386533dd6eSLluís Vilanova     }
73992eecfffSPaolo Bonzini     trace_init_file();
7400572f558SPaolo Bonzini     qemu_plugin_load_list(&plugins, &error_fatal);
7416533dd6eSLluís Vilanova 
74231e31b8aSbellard     /* Zero out regs */
74301ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
74431e31b8aSbellard 
74531e31b8aSbellard     /* Zero out image_info */
74631e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
74731e31b8aSbellard 
748edf8e2afSMika Westerberg     memset(&bprm, 0, sizeof (bprm));
749edf8e2afSMika Westerberg 
75074cd30b8Sbellard     /* Scan interp_prefix dir for replacement files. */
75174cd30b8Sbellard     init_paths(interp_prefix);
75274cd30b8Sbellard 
7534a24a758SPeter Maydell     init_qemu_uname_release();
7544a24a758SPeter Maydell 
7556e1c0d7bSLaurent Vivier     /*
7566e1c0d7bSLaurent Vivier      * Manage binfmt-misc open-binary flag
7576e1c0d7bSLaurent Vivier      */
758768fe76eSYunQiang Su     execfd = qemu_getauxval(AT_EXECFD);
759768fe76eSYunQiang Su     if (execfd == 0) {
7609d3019bcSLaurent Vivier         execfd = open(exec_path, O_RDONLY);
761768fe76eSYunQiang Su         if (execfd < 0) {
7629d3019bcSLaurent Vivier             printf("Error while loading %s: %s\n", exec_path, strerror(errno));
763768fe76eSYunQiang Su             _exit(EXIT_FAILURE);
764768fe76eSYunQiang Su         }
765768fe76eSYunQiang Su     }
766768fe76eSYunQiang Su 
767258bec39SHelge Deller     /* Resolve executable file name to full path name */
768258bec39SHelge Deller     if (realpath(exec_path, real_exec_path)) {
769258bec39SHelge Deller         exec_path = real_exec_path;
770258bec39SHelge Deller     }
771258bec39SHelge Deller 
7726e1c0d7bSLaurent Vivier     /*
7736e1c0d7bSLaurent Vivier      * get binfmt_misc flags
7746e1c0d7bSLaurent Vivier      */
7756e1c0d7bSLaurent Vivier     preserve_argv0 = !!(qemu_getauxval(AT_FLAGS) & AT_FLAGS_PRESERVE_ARGV0);
7766e1c0d7bSLaurent Vivier 
7776e1c0d7bSLaurent Vivier     /*
7786e1c0d7bSLaurent Vivier      * Manage binfmt-misc preserve-arg[0] flag
7796e1c0d7bSLaurent Vivier      *    argv[optind]     full path to the binary
7806e1c0d7bSLaurent Vivier      *    argv[optind + 1] original argv[0]
7816e1c0d7bSLaurent Vivier      */
7826e1c0d7bSLaurent Vivier     if (optind + 1 < argc && preserve_argv0) {
7836e1c0d7bSLaurent Vivier         optind++;
7846e1c0d7bSLaurent Vivier     }
7856e1c0d7bSLaurent Vivier 
78646027c07Sbellard     if (cpu_model == NULL) {
787768fe76eSYunQiang Su         cpu_model = cpu_get_model(get_elf_eflags(execfd));
788aaed909aSbellard     }
789c1c8cfe5SEduardo Habkost     cpu_type = parse_cpu_option(cpu_model);
7902278b939SIgor Mammedov 
79113c13397SRichard Henderson     /* init tcg before creating CPUs */
792940e43aaSClaudio Fontana     {
7933cfb0456SPeter Maydell         AccelState *accel = current_accel();
7943cfb0456SPeter Maydell         AccelClass *ac = ACCEL_GET_CLASS(accel);
7952278b939SIgor Mammedov 
796b86f59c7SClaudio Fontana         accel_init_interfaces(ac);
7973cfb0456SPeter Maydell         object_property_set_bool(OBJECT(accel), "one-insn-per-tb",
7983cfb0456SPeter Maydell                                  opt_one_insn_per_tb, &error_abort);
79992242f34SClaudio Fontana         ac->init_machine(NULL);
800940e43aaSClaudio Fontana     }
801ff8a8bbcSRichard Henderson 
802ff8a8bbcSRichard Henderson     /*
803ff8a8bbcSRichard Henderson      * Finalize page size before creating CPUs.
804ff8a8bbcSRichard Henderson      * This will do nothing if !TARGET_PAGE_BITS_VARY.
805ff8a8bbcSRichard Henderson      * The most efficient setting is to match the host.
806ff8a8bbcSRichard Henderson      */
807ff8a8bbcSRichard Henderson     host_page_size = qemu_real_host_page_size();
808ff8a8bbcSRichard Henderson     set_preferred_target_page_bits(ctz32(host_page_size));
809ff8a8bbcSRichard Henderson     finalize_target_page_bits();
810ff8a8bbcSRichard Henderson 
8112278b939SIgor Mammedov     cpu = cpu_create(cpu_type);
812b77af26eSRichard Henderson     env = cpu_env(cpu);
8130ac46af3SAndreas Färber     cpu_reset(cpu);
814db6b81d4SAndreas Färber     thread_cpu = cpu;
81554936004Sbellard 
8168f67b9c6SRichard Henderson     /*
8178f67b9c6SRichard Henderson      * Reserving too much vm space via mmap can run into problems
8188f67b9c6SRichard Henderson      * with rlimits, oom due to page table creation, etc.  We will
8198f67b9c6SRichard Henderson      * still try it, if directed by the command-line option, but
8208f67b9c6SRichard Henderson      * not by default.
8218f67b9c6SRichard Henderson      */
8228f67b9c6SRichard Henderson     max_reserved_va = MAX_RESERVED_VA(cpu);
8238f67b9c6SRichard Henderson     if (reserved_va != 0) {
82413c13397SRichard Henderson         if ((reserved_va + 1) % host_page_size) {
82513c13397SRichard Henderson             char *s = size_to_str(host_page_size);
8262f7828b5SRichard Henderson             fprintf(stderr, "Reserved virtual address not aligned mod %s\n", s);
8272f7828b5SRichard Henderson             g_free(s);
8282f7828b5SRichard Henderson             exit(EXIT_FAILURE);
8292f7828b5SRichard Henderson         }
8308f67b9c6SRichard Henderson         if (max_reserved_va && reserved_va > max_reserved_va) {
8318f67b9c6SRichard Henderson             fprintf(stderr, "Reserved virtual address too big\n");
8328f67b9c6SRichard Henderson             exit(EXIT_FAILURE);
8338f67b9c6SRichard Henderson         }
8348f67b9c6SRichard Henderson     } else if (HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32) {
83595059f9cSRichard Henderson         /* MAX_RESERVED_VA + 1 is a large power of 2, so is aligned. */
83695059f9cSRichard Henderson         reserved_va = max_reserved_va;
8378f67b9c6SRichard Henderson     }
8388f67b9c6SRichard Henderson 
839c8fb5cf9SRichard Henderson     /*
840c8fb5cf9SRichard Henderson      * Temporarily disable
841c8fb5cf9SRichard Henderson      *   "comparison is always false due to limited range of data type"
842c8fb5cf9SRichard Henderson      * due to comparison between (possible) uint64_t and uintptr_t.
843c8fb5cf9SRichard Henderson      */
844c8fb5cf9SRichard Henderson #pragma GCC diagnostic push
845c8fb5cf9SRichard Henderson #pragma GCC diagnostic ignored "-Wtype-limits"
846c8fb5cf9SRichard Henderson 
847c8fb5cf9SRichard Henderson     /*
848c8fb5cf9SRichard Henderson      * Select an initial value for task_unmapped_base that is in range.
849c8fb5cf9SRichard Henderson      */
850c8fb5cf9SRichard Henderson     if (reserved_va) {
851c8fb5cf9SRichard Henderson         if (TASK_UNMAPPED_BASE < reserved_va) {
852c8fb5cf9SRichard Henderson             task_unmapped_base = TASK_UNMAPPED_BASE;
853c8fb5cf9SRichard Henderson         } else {
854c8fb5cf9SRichard Henderson             /* The most common default formula is TASK_SIZE / 3. */
855c8fb5cf9SRichard Henderson             task_unmapped_base = TARGET_PAGE_ALIGN(reserved_va / 3);
856c8fb5cf9SRichard Henderson         }
857c8fb5cf9SRichard Henderson     } else if (TASK_UNMAPPED_BASE < UINTPTR_MAX) {
858c8fb5cf9SRichard Henderson         task_unmapped_base = TASK_UNMAPPED_BASE;
859c8fb5cf9SRichard Henderson     } else {
860c8fb5cf9SRichard Henderson         /* 32-bit host: pick something medium size. */
861c8fb5cf9SRichard Henderson         task_unmapped_base = 0x10000000;
862c8fb5cf9SRichard Henderson     }
863c8fb5cf9SRichard Henderson     mmap_next_start = task_unmapped_base;
864c8fb5cf9SRichard Henderson 
865da2b71faSRichard Henderson     /* Similarly for elf_et_dyn_base. */
866da2b71faSRichard Henderson     if (reserved_va) {
867da2b71faSRichard Henderson         if (ELF_ET_DYN_BASE < reserved_va) {
868da2b71faSRichard Henderson             elf_et_dyn_base = ELF_ET_DYN_BASE;
869da2b71faSRichard Henderson         } else {
870da2b71faSRichard Henderson             /* The most common default formula is TASK_SIZE / 3 * 2. */
871da2b71faSRichard Henderson             elf_et_dyn_base = TARGET_PAGE_ALIGN(reserved_va / 3) * 2;
872da2b71faSRichard Henderson         }
873da2b71faSRichard Henderson     } else if (ELF_ET_DYN_BASE < UINTPTR_MAX) {
874da2b71faSRichard Henderson         elf_et_dyn_base = ELF_ET_DYN_BASE;
875da2b71faSRichard Henderson     } else {
876da2b71faSRichard Henderson         /* 32-bit host: pick something medium size. */
877da2b71faSRichard Henderson         elf_et_dyn_base = 0x18000000;
878da2b71faSRichard Henderson     }
879da2b71faSRichard Henderson 
880c8fb5cf9SRichard Henderson #pragma GCC diagnostic pop
881c8fb5cf9SRichard Henderson 
882a573e9baSRichard Henderson     {
883a573e9baSRichard Henderson         Error *err = NULL;
8845ebdd774SRichard Henderson         if (seed_optarg != NULL) {
885a573e9baSRichard Henderson             qemu_guest_random_seed_main(seed_optarg, &err);
886a573e9baSRichard Henderson         } else {
887a573e9baSRichard Henderson             qcrypto_init(&err);
888a573e9baSRichard Henderson         }
889a573e9baSRichard Henderson         if (err) {
890a573e9baSRichard Henderson             error_reportf_err(err, "cannot initialize crypto: ");
891a573e9baSRichard Henderson             exit(1);
892a573e9baSRichard Henderson         }
893c5e4a5a9SMagnus Reftel     }
894c5e4a5a9SMagnus Reftel 
89504a6dfebSaurel32     target_environ = envlist_to_environ(envlist, NULL);
89604a6dfebSaurel32     envlist_free(envlist);
897b12b6a18Sths 
898379f6698SPaul Brook     /*
899379f6698SPaul Brook      * Read in mmap_min_addr kernel parameter.  This value is used
900379f6698SPaul Brook      * When loading the ELF image to determine whether guest_base
90114f24e14SRichard Henderson      * is needed.  It is also used in mmap_find_vma.
902379f6698SPaul Brook      */
90314f24e14SRichard Henderson     {
904379f6698SPaul Brook         FILE *fp;
905379f6698SPaul Brook 
906379f6698SPaul Brook         if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
907379f6698SPaul Brook             unsigned long tmp;
908c9f80666SRichard Henderson             if (fscanf(fp, "%lu", &tmp) == 1 && tmp != 0) {
90978b79b2cSRichard Henderson                 mmap_min_addr = MAX(tmp, host_page_size);
910c9f80666SRichard Henderson                 qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n",
911c9f80666SRichard Henderson                               mmap_min_addr);
912379f6698SPaul Brook             }
913379f6698SPaul Brook             fclose(fp);
914379f6698SPaul Brook         }
915379f6698SPaul Brook     }
916379f6698SPaul Brook 
9177d8cec95Saurel32     /*
918c9f80666SRichard Henderson      * We prefer to not make NULL pointers accessible to QEMU.
919c9f80666SRichard Henderson      * If we're in a chroot with no /proc, fall back to 1 page.
920c9f80666SRichard Henderson      */
921c9f80666SRichard Henderson     if (mmap_min_addr == 0) {
922ff8a8bbcSRichard Henderson         mmap_min_addr = host_page_size;
923c9f80666SRichard Henderson         qemu_log_mask(CPU_LOG_PAGE,
924c9f80666SRichard Henderson                       "host mmap_min_addr=0x%lx (fallback)\n",
925c9f80666SRichard Henderson                       mmap_min_addr);
926c9f80666SRichard Henderson     }
927c9f80666SRichard Henderson 
928c9f80666SRichard Henderson     /*
9297d8cec95Saurel32      * Prepare copy of argv vector for target.
9307d8cec95Saurel32      */
9317d8cec95Saurel32     target_argc = argc - optind;
9322ee80bceSNguyen Dinh Phi     target_argv = g_new0(char *, target_argc + 1);
9337d8cec95Saurel32 
9347d8cec95Saurel32     /*
9357d8cec95Saurel32      * If argv0 is specified (using '-0' switch) we replace
9367d8cec95Saurel32      * argv[0] pointer with the given one.
9377d8cec95Saurel32      */
9387d8cec95Saurel32     i = 0;
9397d8cec95Saurel32     if (argv0 != NULL) {
9407d8cec95Saurel32         target_argv[i++] = strdup(argv0);
9417d8cec95Saurel32     }
9427d8cec95Saurel32     for (; i < target_argc; i++) {
9437d8cec95Saurel32         target_argv[i] = strdup(argv[optind + i]);
9447d8cec95Saurel32     }
9457d8cec95Saurel32     target_argv[target_argc] = NULL;
9467d8cec95Saurel32 
947c78d65e8SMarkus Armbruster     ts = g_new0(TaskState, 1);
948edf8e2afSMika Westerberg     init_task_state(ts);
949edf8e2afSMika Westerberg     /* build Task State */
950edf8e2afSMika Westerberg     ts->info = info;
951edf8e2afSMika Westerberg     ts->bprm = &bprm;
9520429a971SAndreas Färber     cpu->opaque = ts;
953edf8e2afSMika Westerberg     task_settid(ts);
954edf8e2afSMika Westerberg 
955c093364fSOwen Anderson     fd_trans_init();
956c093364fSOwen Anderson 
9579d3019bcSLaurent Vivier     ret = loader_exec(execfd, exec_path, target_argv, target_environ, regs,
958fd4d81ddSArnaud Patard         info, &bprm);
959fd4d81ddSArnaud Patard     if (ret != 0) {
9609d3019bcSLaurent Vivier         printf("Error while loading %s: %s\n", exec_path, strerror(-ret));
9614d1275c2SRiku Voipio         _exit(EXIT_FAILURE);
96231e31b8aSbellard     }
96331e31b8aSbellard 
964b12b6a18Sths     for (wrk = target_environ; *wrk; wrk++) {
965ec45bbe5SSaurav Sachidanand         g_free(*wrk);
966b12b6a18Sths     }
967b12b6a18Sths 
968ec45bbe5SSaurav Sachidanand     g_free(target_environ);
969b12b6a18Sths 
97013829020SPaolo Bonzini     if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
97193756fdcSRichard Henderson         FILE *f = qemu_log_trylock();
97293756fdcSRichard Henderson         if (f) {
97393756fdcSRichard Henderson             fprintf(f, "guest_base  %p\n", (void *)guest_base);
97493756fdcSRichard Henderson             fprintf(f, "page layout changed following binary load\n");
97593756fdcSRichard Henderson             page_dump(f);
97654936004Sbellard 
97793756fdcSRichard Henderson             fprintf(f, "end_code    0x" TARGET_ABI_FMT_lx "\n",
97893756fdcSRichard Henderson                     info->end_code);
97993756fdcSRichard Henderson             fprintf(f, "start_code  0x" TARGET_ABI_FMT_lx "\n",
98093756fdcSRichard Henderson                     info->start_code);
98193756fdcSRichard Henderson             fprintf(f, "start_data  0x" TARGET_ABI_FMT_lx "\n",
98293756fdcSRichard Henderson                     info->start_data);
98393756fdcSRichard Henderson             fprintf(f, "end_data    0x" TARGET_ABI_FMT_lx "\n",
98493756fdcSRichard Henderson                     info->end_data);
98593756fdcSRichard Henderson             fprintf(f, "start_stack 0x" TARGET_ABI_FMT_lx "\n",
98693756fdcSRichard Henderson                     info->start_stack);
98793756fdcSRichard Henderson             fprintf(f, "brk         0x" TARGET_ABI_FMT_lx "\n",
98893756fdcSRichard Henderson                     info->brk);
98993756fdcSRichard Henderson             fprintf(f, "entry       0x" TARGET_ABI_FMT_lx "\n",
99093756fdcSRichard Henderson                     info->entry);
99193756fdcSRichard Henderson             fprintf(f, "argv_start  0x" TARGET_ABI_FMT_lx "\n",
99260f1c801SRichard Henderson                     info->argv);
99393756fdcSRichard Henderson             fprintf(f, "env_start   0x" TARGET_ABI_FMT_lx "\n",
99460f1c801SRichard Henderson                     info->envp);
99593756fdcSRichard Henderson             fprintf(f, "auxv_start  0x" TARGET_ABI_FMT_lx "\n",
99693756fdcSRichard Henderson                     info->saved_auxv);
99793756fdcSRichard Henderson             qemu_log_unlock(f);
99893756fdcSRichard Henderson         }
9992e77eac6Sblueswir1     }
100031e31b8aSbellard 
100153a5960aSpbrook     target_set_brk(info->brk);
100231e31b8aSbellard     syscall_init();
100366fb9763Sbellard     signal_init();
100431e31b8aSbellard 
10059002ec79SRichard Henderson     /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
10069002ec79SRichard Henderson        generating the prologue until now so that the prologue can take
10079002ec79SRichard Henderson        the real value of GUEST_BASE into account.  */
1008935f75aeSRichard Henderson     tcg_prologue_init();
10099002ec79SRichard Henderson 
1010cd71c089SLaurent Vivier     target_cpu_copy_regs(env, regs);
1011cd71c089SLaurent Vivier 
1012fcedd920SAlex Bennée     if (gdbstub) {
1013fcedd920SAlex Bennée         if (gdbserver_start(gdbstub) < 0) {
1014fcedd920SAlex Bennée             fprintf(stderr, "qemu: could not open gdbserver on %s\n",
1015fcedd920SAlex Bennée                     gdbstub);
10164d1275c2SRiku Voipio             exit(EXIT_FAILURE);
1017ff7a981aSPeter Maydell         }
1018f84e313eSGustavo Romero         gdb_handlesig(cpu, 0, NULL, NULL, 0);
10191fddef4bSbellard     }
1020e4a4aaa5SRichard Henderson 
1021e4a4aaa5SRichard Henderson #ifdef CONFIG_SEMIHOSTING
1022e4a4aaa5SRichard Henderson     qemu_semihosting_guestfd_init();
1023e4a4aaa5SRichard Henderson #endif
1024e4a4aaa5SRichard Henderson 
10251b6b029eSbellard     cpu_loop(env);
10261b6b029eSbellard     /* never exits */
102731e31b8aSbellard     return 0;
102831e31b8aSbellard }
1029