xref: /qemu/linux-user/main.c (revision d4e1369a)
131e31b8aSbellard /*
293ac68bcSbellard  *  qemu user main
331e31b8aSbellard  *
468d0f70eSbellard  *  Copyright (c) 2003-2008 Fabrice Bellard
531e31b8aSbellard  *
631e31b8aSbellard  *  This program is free software; you can redistribute it and/or modify
731e31b8aSbellard  *  it under the terms of the GNU General Public License as published by
831e31b8aSbellard  *  the Free Software Foundation; either version 2 of the License, or
931e31b8aSbellard  *  (at your option) any later version.
1031e31b8aSbellard  *
1131e31b8aSbellard  *  This program is distributed in the hope that it will be useful,
1231e31b8aSbellard  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1331e31b8aSbellard  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1431e31b8aSbellard  *  GNU General Public License for more details.
1531e31b8aSbellard  *
1631e31b8aSbellard  *  You should have received a copy of the GNU General Public License
178167ee88SBlue Swirl  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
1831e31b8aSbellard  */
1914a48c1dSMarkus Armbruster 
20d39594e9SPeter Maydell #include "qemu/osdep.h"
2149f95221SMarc-André Lureau #include "qemu/help-texts.h"
22b52713c1SPhilippe Mathieu-Daudé #include "qemu/units.h"
23940e43aaSClaudio Fontana #include "qemu/accel.h"
2467a1de0dSFam Zheng #include "qemu-version.h"
25edf8e2afSMika Westerberg #include <sys/syscall.h>
26703e0e89SRichard Henderson #include <sys/resource.h>
27ee947430SAlex Bennée #include <sys/shm.h>
286e1c0d7bSLaurent Vivier #include <linux/binfmts.h>
2931e31b8aSbellard 
30daa76aa4SMarkus Armbruster #include "qapi/error.h"
313ef693a0Sbellard #include "qemu.h"
323b249d26SPeter Maydell #include "user-internals.h"
33f348b6d1SVeronia Bahaa #include "qemu/path.h"
34dc5e9ac7SMarkus Armbruster #include "qemu/queue.h"
356533dd6eSLluís Vilanova #include "qemu/config-file.h"
36f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
37f5852efaSChristophe Fergeau #include "qemu/error-report.h"
38f348b6d1SVeronia Bahaa #include "qemu/help_option.h"
390b8fa32fSMarkus Armbruster #include "qemu/module.h"
40f308f64eSLluís Vilanova #include "qemu/plugin.h"
4163c91552SPaolo Bonzini #include "exec/exec-all.h"
4285b4fa0cSPeter Maydell #include "exec/gdbstub.h"
43d96bf49bSAlex Bennée #include "gdbstub/user.h"
44d7ec12f8SRichard Henderson #include "tcg/startup.h"
451de7afc9SPaolo Bonzini #include "qemu/timer.h"
461de7afc9SPaolo Bonzini #include "qemu/envlist.h"
475ebdd774SRichard Henderson #include "qemu/guest-random.h"
48d8fd2954SPaul Brook #include "elf.h"
496533dd6eSLluís Vilanova #include "trace/control.h"
50542ca434SLaurent Vivier #include "target_elf.h"
51cd71c089SLaurent Vivier #include "cpu_loop-common.h"
52a573e9baSRichard Henderson #include "crypto/init.h"
53c093364fSOwen Anderson #include "fd-trans.h"
542113aed6SPeter Maydell #include "signal-common.h"
553ad0a769SPeter Maydell #include "loader.h"
565423e6d3SPeter Maydell #include "user-mmap.h"
57327b75a4SIlya Leoshkevich #include "tcg/perf.h"
58ff8a8bbcSRichard Henderson #include "exec/page-vary.h"
5904a6dfebSaurel32 
60e4a4aaa5SRichard Henderson #ifdef CONFIG_SEMIHOSTING
61e4a4aaa5SRichard Henderson #include "semihosting/semihost.h"
62e4a4aaa5SRichard Henderson #endif
63e4a4aaa5SRichard Henderson 
646e1c0d7bSLaurent Vivier #ifndef AT_FLAGS_PRESERVE_ARGV0
656e1c0d7bSLaurent Vivier #define AT_FLAGS_PRESERVE_ARGV0_BIT 0
666e1c0d7bSLaurent Vivier #define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
676e1c0d7bSLaurent Vivier #endif
686e1c0d7bSLaurent Vivier 
69d088d664Saurel32 char *exec_path;
70258bec39SHelge Deller char real_exec_path[PATH_MAX];
71d088d664Saurel32 
723cfb0456SPeter Maydell static bool opt_one_insn_per_tb;
738cb76755SStefan Weil static const char *argv0;
74fcedd920SAlex Bennée static const char *gdbstub;
758cb76755SStefan Weil static envlist_t *envlist;
7651fb256aSAndreas Färber static const char *cpu_model;
772278b939SIgor Mammedov static const char *cpu_type;
785ebdd774SRichard Henderson static const char *seed_optarg;
79379f6698SPaul Brook unsigned long mmap_min_addr;
805ca870b9SRichard Henderson uintptr_t guest_base;
81e307c192SRichard Henderson bool have_guest_base;
82120a9848SPaolo Bonzini 
83288e65b9SAlexander Graf /*
844b25a506SJosh Kunz  * Used to implement backwards-compatibility for the `-strace`, and
854b25a506SJosh Kunz  * QEMU_STRACE options. Without this, the QEMU_LOG can be overwritten by
864b25a506SJosh Kunz  * -strace, or vice versa.
874b25a506SJosh Kunz  */
884b25a506SJosh Kunz static bool enable_strace;
894b25a506SJosh Kunz 
904b25a506SJosh Kunz /*
914b25a506SJosh Kunz  * The last log mask given by the user in an environment variable or argument.
924b25a506SJosh Kunz  * Used to support command line arguments overriding environment variables.
934b25a506SJosh Kunz  */
944b25a506SJosh Kunz static int last_log_mask;
95b410253fSRichard Henderson static const char *last_log_filename;
964b25a506SJosh Kunz 
974b25a506SJosh Kunz /*
98288e65b9SAlexander Graf  * When running 32-on-64 we should make sure we can fit all of the possible
99288e65b9SAlexander Graf  * guest address space into a contiguous chunk of virtual host memory.
100288e65b9SAlexander Graf  *
101288e65b9SAlexander Graf  * This way we will never overlap with our own libraries or binaries or stack
102288e65b9SAlexander Graf  * or anything else that QEMU maps.
10318e80c55SRichard Henderson  *
10418e80c55SRichard Henderson  * Many cpus reserve the high bit (or more than one for some 64-bit cpus)
10518e80c55SRichard Henderson  * of the address for the kernel.  Some cpus rely on this and user space
10618e80c55SRichard Henderson  * uses the high bit(s) for pointer tagging and the like.  For them, we
10718e80c55SRichard Henderson  * must preserve the expected address space.
108288e65b9SAlexander Graf  */
10918e80c55SRichard Henderson #ifndef MAX_RESERVED_VA
11018e80c55SRichard Henderson # if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
11118e80c55SRichard Henderson #  if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \
11218e80c55SRichard Henderson       (TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
11395059f9cSRichard Henderson #   define MAX_RESERVED_VA(CPU)  0xfffffffful
114314992b1SAlexander Graf #  else
11595059f9cSRichard Henderson #   define MAX_RESERVED_VA(CPU)  ((1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1)
116314992b1SAlexander Graf #  endif
117288e65b9SAlexander Graf # else
1188f67b9c6SRichard Henderson #  define MAX_RESERVED_VA(CPU)  0
11918e80c55SRichard Henderson # endif
12018e80c55SRichard Henderson #endif
12118e80c55SRichard Henderson 
12268a1c816SPaul Brook unsigned long reserved_va;
1231b530a6dSaurel32 
124d03f9c32SMeador Inge static void usage(int exitcode);
125fc9c5412SJohannes Schauer 
1267ee2822cSPaolo Bonzini static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
127e586822aSRiku Voipio const char *qemu_uname_release;
128586314f2Sbellard 
1290a3346b5SHelge Deller #if !defined(TARGET_DEFAULT_STACK_SIZE)
1309de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
1319de5e440Sbellard    we allocate a bigger stack. Need a better solution, for example
1329de5e440Sbellard    by remapping the process stack directly at the right place */
1330a3346b5SHelge Deller #define TARGET_DEFAULT_STACK_SIZE	8 * 1024 * 1024UL
1340a3346b5SHelge Deller #endif
1350a3346b5SHelge Deller 
1360a3346b5SHelge Deller unsigned long guest_stack_size = TARGET_DEFAULT_STACK_SIZE;
13731e31b8aSbellard 
138d5975363Spbrook /***********************************************************/
139d5975363Spbrook /* Helper routines for implementing atomic operations.  */
140d5975363Spbrook 
141d5975363Spbrook /* Make sure everything is in a consistent state for calling fork().  */
142d5975363Spbrook void fork_start(void)
143d5975363Spbrook {
14406065c45SPeter Maydell     start_exclusive();
145d032d1b4SRiku Voipio     mmap_fork_start();
146024949caSPeter Maydell     cpu_list_lock();
147f7e15affSAlex Bennée     qemu_plugin_user_prefork_lock();
148d5975363Spbrook }
149d5975363Spbrook 
150d5975363Spbrook void fork_end(int child)
151d5975363Spbrook {
152f7e15affSAlex Bennée     qemu_plugin_user_postfork(child);
153d032d1b4SRiku Voipio     mmap_fork_end(child);
154d5975363Spbrook     if (child) {
155bdc44640SAndreas Färber         CPUState *cpu, *next_cpu;
156d5975363Spbrook         /* Child processes created by fork() only have a single thread.
157d5975363Spbrook            Discard information about the parent threads.  */
158bdc44640SAndreas Färber         CPU_FOREACH_SAFE(cpu, next_cpu) {
159bdc44640SAndreas Färber             if (cpu != thread_cpu) {
1603c55dd58SPhilippe Mathieu-Daudé                 QTAILQ_REMOVE_RCU(&cpus_queue, cpu, node);
161bdc44640SAndreas Färber             }
162bdc44640SAndreas Färber         }
163267f685bSPaolo Bonzini         qemu_init_cpu_list();
164*d4e1369aSIlya Leoshkevich         get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
165f7ec7f7bSPeter Crosthwaite         gdbserver_fork(thread_cpu);
166d5975363Spbrook     } else {
167267f685bSPaolo Bonzini         cpu_list_unlock();
168d5975363Spbrook     }
1697de0816fSIlya Leoshkevich     /*
1707de0816fSIlya Leoshkevich      * qemu_init_cpu_list() reinitialized the child exclusive state, but we
1717de0816fSIlya Leoshkevich      * also need to keep current_cpu consistent, so call end_exclusive() for
1727de0816fSIlya Leoshkevich      * both child and parent.
1737de0816fSIlya Leoshkevich      */
1747de0816fSIlya Leoshkevich     end_exclusive();
175d5975363Spbrook }
176d5975363Spbrook 
177b44316fbSPeter Maydell __thread CPUState *thread_cpu;
17859faf6d6Sbellard 
179178f9429SSergey Fedorov bool qemu_cpu_is_self(CPUState *cpu)
180178f9429SSergey Fedorov {
181178f9429SSergey Fedorov     return thread_cpu == cpu;
182178f9429SSergey Fedorov }
183178f9429SSergey Fedorov 
184178f9429SSergey Fedorov void qemu_cpu_kick(CPUState *cpu)
185178f9429SSergey Fedorov {
186178f9429SSergey Fedorov     cpu_exit(cpu);
187178f9429SSergey Fedorov }
188178f9429SSergey Fedorov 
189edf8e2afSMika Westerberg void task_settid(TaskState *ts)
190edf8e2afSMika Westerberg {
191edf8e2afSMika Westerberg     if (ts->ts_tid == 0) {
192edf8e2afSMika Westerberg         ts->ts_tid = (pid_t)syscall(SYS_gettid);
193edf8e2afSMika Westerberg     }
194edf8e2afSMika Westerberg }
195edf8e2afSMika Westerberg 
196edf8e2afSMika Westerberg void stop_all_tasks(void)
197edf8e2afSMika Westerberg {
198edf8e2afSMika Westerberg     /*
199edf8e2afSMika Westerberg      * We trust that when using NPTL, start_exclusive()
200edf8e2afSMika Westerberg      * handles thread stopping correctly.
201edf8e2afSMika Westerberg      */
202edf8e2afSMika Westerberg     start_exclusive();
203edf8e2afSMika Westerberg }
204edf8e2afSMika Westerberg 
205c3a92833Spbrook /* Assumes contents are already zeroed.  */
206624f7979Spbrook void init_task_state(TaskState *ts)
207624f7979Spbrook {
208eb33cdaeSCameron Esfahani     long ticks_per_sec;
209eb33cdaeSCameron Esfahani     struct timespec bt;
210eb33cdaeSCameron Esfahani 
211624f7979Spbrook     ts->used = 1;
2125bfce0b7SPeter Maydell     ts->sigaltstack_used = (struct target_sigaltstack) {
2135bfce0b7SPeter Maydell         .ss_sp = 0,
2145bfce0b7SPeter Maydell         .ss_size = 0,
2155bfce0b7SPeter Maydell         .ss_flags = TARGET_SS_DISABLE,
2165bfce0b7SPeter Maydell     };
217eb33cdaeSCameron Esfahani 
218eb33cdaeSCameron Esfahani     /* Capture task start time relative to system boot */
219eb33cdaeSCameron Esfahani 
220eb33cdaeSCameron Esfahani     ticks_per_sec = sysconf(_SC_CLK_TCK);
221eb33cdaeSCameron Esfahani 
222eb33cdaeSCameron Esfahani     if ((ticks_per_sec > 0) && !clock_gettime(CLOCK_BOOTTIME, &bt)) {
223eb33cdaeSCameron Esfahani         /* start_boottime is expressed in clock ticks */
224eb33cdaeSCameron Esfahani         ts->start_boottime = bt.tv_sec * (uint64_t) ticks_per_sec;
225eb33cdaeSCameron Esfahani         ts->start_boottime += bt.tv_nsec * (uint64_t) ticks_per_sec /
226eb33cdaeSCameron Esfahani                               NANOSECONDS_PER_SECOND;
227eb33cdaeSCameron Esfahani     }
228624f7979Spbrook }
2299de5e440Sbellard 
23030ba0ee5SAndreas Färber CPUArchState *cpu_copy(CPUArchState *env)
23130ba0ee5SAndreas Färber {
23229a0af61SRichard Henderson     CPUState *cpu = env_cpu(env);
2332278b939SIgor Mammedov     CPUState *new_cpu = cpu_create(cpu_type);
234b77af26eSRichard Henderson     CPUArchState *new_env = cpu_env(new_cpu);
23530ba0ee5SAndreas Färber     CPUBreakpoint *bp;
23630ba0ee5SAndreas Färber 
23730ba0ee5SAndreas Färber     /* Reset non arch specific state */
23875a34036SAndreas Färber     cpu_reset(new_cpu);
23930ba0ee5SAndreas Färber 
2406cc9d67cSRichard Henderson     new_cpu->tcg_cflags = cpu->tcg_cflags;
24130ba0ee5SAndreas Färber     memcpy(new_env, env, sizeof(CPUArchState));
2422732c739Sfanwj@mail.ustc.edu.cn #if defined(TARGET_I386) || defined(TARGET_X86_64)
2432732c739Sfanwj@mail.ustc.edu.cn     new_env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
2442732c739Sfanwj@mail.ustc.edu.cn                                     PROT_READ | PROT_WRITE,
2452732c739Sfanwj@mail.ustc.edu.cn                                     MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2462732c739Sfanwj@mail.ustc.edu.cn     memcpy(g2h_untagged(new_env->gdt.base), g2h_untagged(env->gdt.base),
2472732c739Sfanwj@mail.ustc.edu.cn            sizeof(uint64_t) * TARGET_GDT_ENTRIES);
2482732c739Sfanwj@mail.ustc.edu.cn     OBJECT(new_cpu)->free = OBJECT(cpu)->free;
2492732c739Sfanwj@mail.ustc.edu.cn #endif
25030ba0ee5SAndreas Färber 
25130ba0ee5SAndreas Färber     /* Clone all break/watchpoints.
25230ba0ee5SAndreas Färber        Note: Once we support ptrace with hw-debug register access, make sure
25330ba0ee5SAndreas Färber        BP_CPU break/watchpoints are handled correctly on clone. */
2541d085f6cSThierry Bultel     QTAILQ_INIT(&new_cpu->breakpoints);
255f0c3c505SAndreas Färber     QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
256b3310ab3SAndreas Färber         cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
25730ba0ee5SAndreas Färber     }
25830ba0ee5SAndreas Färber 
25930ba0ee5SAndreas Färber     return new_env;
26030ba0ee5SAndreas Färber }
26130ba0ee5SAndreas Färber 
262fc9c5412SJohannes Schauer static void handle_arg_help(const char *arg)
263fc9c5412SJohannes Schauer {
2644d1275c2SRiku Voipio     usage(EXIT_SUCCESS);
265fc9c5412SJohannes Schauer }
266fc9c5412SJohannes Schauer 
267fc9c5412SJohannes Schauer static void handle_arg_log(const char *arg)
268fc9c5412SJohannes Schauer {
2694b25a506SJosh Kunz     last_log_mask = qemu_str_to_log_mask(arg);
2704b25a506SJosh Kunz     if (!last_log_mask) {
27159a6fa6eSPeter Maydell         qemu_print_log_usage(stdout);
2724d1275c2SRiku Voipio         exit(EXIT_FAILURE);
273fc9c5412SJohannes Schauer     }
274fc9c5412SJohannes Schauer }
275fc9c5412SJohannes Schauer 
2768423fa90SAlex Bennée static void handle_arg_dfilter(const char *arg)
2778423fa90SAlex Bennée {
2787f4341e8SAlex Bennée     qemu_set_dfilter_ranges(arg, &error_fatal);
2798423fa90SAlex Bennée }
2808423fa90SAlex Bennée 
28150171d42S陳韋任 static void handle_arg_log_filename(const char *arg)
28250171d42S陳韋任 {
283b410253fSRichard Henderson     last_log_filename = arg;
28450171d42S陳韋任 }
28550171d42S陳韋任 
286fc9c5412SJohannes Schauer static void handle_arg_set_env(const char *arg)
287fc9c5412SJohannes Schauer {
288fc9c5412SJohannes Schauer     char *r, *p, *token;
289fc9c5412SJohannes Schauer     r = p = strdup(arg);
290fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
291fc9c5412SJohannes Schauer         if (envlist_setenv(envlist, token) != 0) {
2924d1275c2SRiku Voipio             usage(EXIT_FAILURE);
293fc9c5412SJohannes Schauer         }
294fc9c5412SJohannes Schauer     }
295fc9c5412SJohannes Schauer     free(r);
296fc9c5412SJohannes Schauer }
297fc9c5412SJohannes Schauer 
298fc9c5412SJohannes Schauer static void handle_arg_unset_env(const char *arg)
299fc9c5412SJohannes Schauer {
300fc9c5412SJohannes Schauer     char *r, *p, *token;
301fc9c5412SJohannes Schauer     r = p = strdup(arg);
302fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
303fc9c5412SJohannes Schauer         if (envlist_unsetenv(envlist, token) != 0) {
3044d1275c2SRiku Voipio             usage(EXIT_FAILURE);
305fc9c5412SJohannes Schauer         }
306fc9c5412SJohannes Schauer     }
307fc9c5412SJohannes Schauer     free(r);
308fc9c5412SJohannes Schauer }
309fc9c5412SJohannes Schauer 
310fc9c5412SJohannes Schauer static void handle_arg_argv0(const char *arg)
311fc9c5412SJohannes Schauer {
312fc9c5412SJohannes Schauer     argv0 = strdup(arg);
313fc9c5412SJohannes Schauer }
314fc9c5412SJohannes Schauer 
315fc9c5412SJohannes Schauer static void handle_arg_stack_size(const char *arg)
316fc9c5412SJohannes Schauer {
317fc9c5412SJohannes Schauer     char *p;
318fc9c5412SJohannes Schauer     guest_stack_size = strtoul(arg, &p, 0);
319fc9c5412SJohannes Schauer     if (guest_stack_size == 0) {
3204d1275c2SRiku Voipio         usage(EXIT_FAILURE);
321fc9c5412SJohannes Schauer     }
322fc9c5412SJohannes Schauer 
323fc9c5412SJohannes Schauer     if (*p == 'M') {
324b52713c1SPhilippe Mathieu-Daudé         guest_stack_size *= MiB;
325fc9c5412SJohannes Schauer     } else if (*p == 'k' || *p == 'K') {
326b52713c1SPhilippe Mathieu-Daudé         guest_stack_size *= KiB;
327fc9c5412SJohannes Schauer     }
328fc9c5412SJohannes Schauer }
329fc9c5412SJohannes Schauer 
330fc9c5412SJohannes Schauer static void handle_arg_ld_prefix(const char *arg)
331fc9c5412SJohannes Schauer {
332fc9c5412SJohannes Schauer     interp_prefix = strdup(arg);
333fc9c5412SJohannes Schauer }
334fc9c5412SJohannes Schauer 
335fc9c5412SJohannes Schauer static void handle_arg_pagesize(const char *arg)
336fc9c5412SJohannes Schauer {
33701e44980SRichard Henderson     unsigned size, want = qemu_real_host_page_size();
33801e44980SRichard Henderson 
33901e44980SRichard Henderson     if (qemu_strtoui(arg, NULL, 10, &size) || size != want) {
34001e44980SRichard Henderson         warn_report("Deprecated page size option cannot "
34101e44980SRichard Henderson                     "change host page size (%u)", want);
342fc9c5412SJohannes Schauer     }
343fc9c5412SJohannes Schauer }
344fc9c5412SJohannes Schauer 
3455ebdd774SRichard Henderson static void handle_arg_seed(const char *arg)
346c5e4a5a9SMagnus Reftel {
3475ebdd774SRichard Henderson     seed_optarg = arg;
348c5e4a5a9SMagnus Reftel }
349c5e4a5a9SMagnus Reftel 
350fc9c5412SJohannes Schauer static void handle_arg_gdb(const char *arg)
351fc9c5412SJohannes Schauer {
352fcedd920SAlex Bennée     gdbstub = g_strdup(arg);
353fc9c5412SJohannes Schauer }
354fc9c5412SJohannes Schauer 
355fc9c5412SJohannes Schauer static void handle_arg_uname(const char *arg)
356fc9c5412SJohannes Schauer {
357fc9c5412SJohannes Schauer     qemu_uname_release = strdup(arg);
358fc9c5412SJohannes Schauer }
359fc9c5412SJohannes Schauer 
360fc9c5412SJohannes Schauer static void handle_arg_cpu(const char *arg)
361fc9c5412SJohannes Schauer {
362fc9c5412SJohannes Schauer     cpu_model = strdup(arg);
363c8057f95SPeter Maydell     if (cpu_model == NULL || is_help_option(cpu_model)) {
364b67e5cb4SThomas Huth         list_cpus();
3654d1275c2SRiku Voipio         exit(EXIT_FAILURE);
366fc9c5412SJohannes Schauer     }
367fc9c5412SJohannes Schauer }
368fc9c5412SJohannes Schauer 
369fc9c5412SJohannes Schauer static void handle_arg_guest_base(const char *arg)
370fc9c5412SJohannes Schauer {
371fc9c5412SJohannes Schauer     guest_base = strtol(arg, NULL, 0);
372e307c192SRichard Henderson     have_guest_base = true;
373fc9c5412SJohannes Schauer }
374fc9c5412SJohannes Schauer 
375fc9c5412SJohannes Schauer static void handle_arg_reserved_va(const char *arg)
376fc9c5412SJohannes Schauer {
377fc9c5412SJohannes Schauer     char *p;
378fc9c5412SJohannes Schauer     int shift = 0;
37995059f9cSRichard Henderson     unsigned long val;
38095059f9cSRichard Henderson 
38195059f9cSRichard Henderson     val = strtoul(arg, &p, 0);
382fc9c5412SJohannes Schauer     switch (*p) {
383fc9c5412SJohannes Schauer     case 'k':
384fc9c5412SJohannes Schauer     case 'K':
385fc9c5412SJohannes Schauer         shift = 10;
386fc9c5412SJohannes Schauer         break;
387fc9c5412SJohannes Schauer     case 'M':
388fc9c5412SJohannes Schauer         shift = 20;
389fc9c5412SJohannes Schauer         break;
390fc9c5412SJohannes Schauer     case 'G':
391fc9c5412SJohannes Schauer         shift = 30;
392fc9c5412SJohannes Schauer         break;
393fc9c5412SJohannes Schauer     }
394fc9c5412SJohannes Schauer     if (shift) {
39595059f9cSRichard Henderson         unsigned long unshifted = val;
396fc9c5412SJohannes Schauer         p++;
39795059f9cSRichard Henderson         val <<= shift;
39895059f9cSRichard Henderson         if (val >> shift != unshifted) {
399fc9c5412SJohannes Schauer             fprintf(stderr, "Reserved virtual address too big\n");
4004d1275c2SRiku Voipio             exit(EXIT_FAILURE);
401fc9c5412SJohannes Schauer         }
402fc9c5412SJohannes Schauer     }
403fc9c5412SJohannes Schauer     if (*p) {
404fc9c5412SJohannes Schauer         fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
4054d1275c2SRiku Voipio         exit(EXIT_FAILURE);
406fc9c5412SJohannes Schauer     }
40795059f9cSRichard Henderson     /* The representation is size - 1, with 0 remaining "default". */
40895059f9cSRichard Henderson     reserved_va = val ? val - 1 : 0;
409fc9c5412SJohannes Schauer }
410fc9c5412SJohannes Schauer 
411e99c1f89SPeter Maydell static void handle_arg_one_insn_per_tb(const char *arg)
412fc9c5412SJohannes Schauer {
4133cfb0456SPeter Maydell     opt_one_insn_per_tb = true;
414fc9c5412SJohannes Schauer }
415fc9c5412SJohannes Schauer 
416fc9c5412SJohannes Schauer static void handle_arg_strace(const char *arg)
417fc9c5412SJohannes Schauer {
4184b25a506SJosh Kunz     enable_strace = true;
419fc9c5412SJohannes Schauer }
420fc9c5412SJohannes Schauer 
421fc9c5412SJohannes Schauer static void handle_arg_version(const char *arg)
422fc9c5412SJohannes Schauer {
4237e563bfbSThomas Huth     printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
4240781dd6eSThomas Huth            "\n" QEMU_COPYRIGHT "\n");
4254d1275c2SRiku Voipio     exit(EXIT_SUCCESS);
426fc9c5412SJohannes Schauer }
427fc9c5412SJohannes Schauer 
4286533dd6eSLluís Vilanova static void handle_arg_trace(const char *arg)
4296533dd6eSLluís Vilanova {
43092eecfffSPaolo Bonzini     trace_opt_parse(arg);
4316533dd6eSLluís Vilanova }
4326533dd6eSLluís Vilanova 
433130ea832SMax Filippov #if defined(TARGET_XTENSA)
434130ea832SMax Filippov static void handle_arg_abi_call0(const char *arg)
435130ea832SMax Filippov {
436130ea832SMax Filippov     xtensa_set_abi_call0();
437130ea832SMax Filippov }
438130ea832SMax Filippov #endif
439130ea832SMax Filippov 
4405584e2dbSIlya Leoshkevich static void handle_arg_perfmap(const char *arg)
4415584e2dbSIlya Leoshkevich {
4425584e2dbSIlya Leoshkevich     perf_enable_perfmap();
4435584e2dbSIlya Leoshkevich }
4445584e2dbSIlya Leoshkevich 
4455584e2dbSIlya Leoshkevich static void handle_arg_jitdump(const char *arg)
4465584e2dbSIlya Leoshkevich {
4475584e2dbSIlya Leoshkevich     perf_enable_jitdump();
4485584e2dbSIlya Leoshkevich }
4495584e2dbSIlya Leoshkevich 
450f308f64eSLluís Vilanova static QemuPluginList plugins = QTAILQ_HEAD_INITIALIZER(plugins);
451f308f64eSLluís Vilanova 
452f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
453f308f64eSLluís Vilanova static void handle_arg_plugin(const char *arg)
454f308f64eSLluís Vilanova {
455f308f64eSLluís Vilanova     qemu_plugin_opt_parse(arg, &plugins);
456f308f64eSLluís Vilanova }
457f308f64eSLluís Vilanova #endif
458f308f64eSLluís Vilanova 
459fc9c5412SJohannes Schauer struct qemu_argument {
460fc9c5412SJohannes Schauer     const char *argv;
461fc9c5412SJohannes Schauer     const char *env;
462fc9c5412SJohannes Schauer     bool has_arg;
463fc9c5412SJohannes Schauer     void (*handle_opt)(const char *arg);
464fc9c5412SJohannes Schauer     const char *example;
465fc9c5412SJohannes Schauer     const char *help;
466fc9c5412SJohannes Schauer };
467fc9c5412SJohannes Schauer 
46842644ceeSJim Meyering static const struct qemu_argument arg_table[] = {
469fc9c5412SJohannes Schauer     {"h",          "",                 false, handle_arg_help,
470fc9c5412SJohannes Schauer      "",           "print this help"},
471daaf8c8eSMeador Inge     {"help",       "",                 false, handle_arg_help,
472daaf8c8eSMeador Inge      "",           ""},
473fc9c5412SJohannes Schauer     {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
474fc9c5412SJohannes Schauer      "port",       "wait gdb connection to 'port'"},
475fc9c5412SJohannes Schauer     {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
476fc9c5412SJohannes Schauer      "path",       "set the elf interpreter prefix to 'path'"},
477fc9c5412SJohannes Schauer     {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
478fc9c5412SJohannes Schauer      "size",       "set the stack size to 'size' bytes"},
479fc9c5412SJohannes Schauer     {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
480c8057f95SPeter Maydell      "model",      "select CPU (-cpu help for list)"},
481fc9c5412SJohannes Schauer     {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
482fc9c5412SJohannes Schauer      "var=value",  "sets targets environment variable (see below)"},
483fc9c5412SJohannes Schauer     {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
484fc9c5412SJohannes Schauer      "var",        "unsets targets environment variable (see below)"},
485fc9c5412SJohannes Schauer     {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
486fc9c5412SJohannes Schauer      "argv0",      "forces target process argv[0] to be 'argv0'"},
487fc9c5412SJohannes Schauer     {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
488fc9c5412SJohannes Schauer      "uname",      "set qemu uname release string to 'uname'"},
489fc9c5412SJohannes Schauer     {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
490fc9c5412SJohannes Schauer      "address",    "set guest_base address to 'address'"},
491fc9c5412SJohannes Schauer     {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
492fc9c5412SJohannes Schauer      "size",       "reserve 'size' bytes for guest virtual address space"},
493fc9c5412SJohannes Schauer     {"d",          "QEMU_LOG",         true,  handle_arg_log,
494989b697dSPeter Maydell      "item[,...]", "enable logging of specified items "
495989b697dSPeter Maydell      "(use '-d help' for a list of items)"},
4968423fa90SAlex Bennée     {"dfilter",    "QEMU_DFILTER",     true,  handle_arg_dfilter,
4978423fa90SAlex Bennée      "range[,...]","filter logging based on address range"},
49850171d42S陳韋任     {"D",          "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
499989b697dSPeter Maydell      "logfile",     "write logs to 'logfile' (default stderr)"},
500fc9c5412SJohannes Schauer     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
50101e44980SRichard Henderson      "pagesize",   "deprecated change to host page size"},
502e99c1f89SPeter Maydell     {"one-insn-per-tb",
503e99c1f89SPeter Maydell                    "QEMU_ONE_INSN_PER_TB",  false, handle_arg_one_insn_per_tb,
504e99c1f89SPeter Maydell      "",           "run with one guest instruction per emulated TB"},
505fc9c5412SJohannes Schauer     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
506fc9c5412SJohannes Schauer      "",           "log system calls"},
5075ebdd774SRichard Henderson     {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_seed,
508c5e4a5a9SMagnus Reftel      "",           "Seed for pseudo-random number generator"},
5096533dd6eSLluís Vilanova     {"trace",      "QEMU_TRACE",       true,  handle_arg_trace,
5106533dd6eSLluís Vilanova      "",           "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
511f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
512f308f64eSLluís Vilanova     {"plugin",     "QEMU_PLUGIN",      true,  handle_arg_plugin,
5133a445acbSMahmoud Mandour      "",           "[file=]<file>[,<argname>=<argvalue>]"},
514f308f64eSLluís Vilanova #endif
515fc9c5412SJohannes Schauer     {"version",    "QEMU_VERSION",     false, handle_arg_version,
5161386d4c0SPeter Maydell      "",           "display version information and exit"},
517130ea832SMax Filippov #if defined(TARGET_XTENSA)
518130ea832SMax Filippov     {"xtensa-abi-call0", "QEMU_XTENSA_ABI_CALL0", false, handle_arg_abi_call0,
519130ea832SMax Filippov      "",           "assume CALL0 Xtensa ABI"},
520130ea832SMax Filippov #endif
5215584e2dbSIlya Leoshkevich     {"perfmap",    "QEMU_PERFMAP",     false, handle_arg_perfmap,
5225584e2dbSIlya Leoshkevich      "",           "Generate a /tmp/perf-${pid}.map file for perf"},
5235584e2dbSIlya Leoshkevich     {"jitdump",    "QEMU_JITDUMP",     false, handle_arg_jitdump,
5245584e2dbSIlya Leoshkevich      "",           "Generate a jit-${pid}.dump file for perf"},
525fc9c5412SJohannes Schauer     {NULL, NULL, false, NULL, NULL, NULL}
526fc9c5412SJohannes Schauer };
527fc9c5412SJohannes Schauer 
528d03f9c32SMeador Inge static void usage(int exitcode)
529fc9c5412SJohannes Schauer {
53042644ceeSJim Meyering     const struct qemu_argument *arginfo;
531fc9c5412SJohannes Schauer     int maxarglen;
532fc9c5412SJohannes Schauer     int maxenvlen;
533fc9c5412SJohannes Schauer 
5342e59915dSPaolo Bonzini     printf("usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
5352e59915dSPaolo Bonzini            "Linux CPU emulator (compiled for " TARGET_NAME " emulation)\n"
536fc9c5412SJohannes Schauer            "\n"
537fc9c5412SJohannes Schauer            "Options and associated environment variables:\n"
538fc9c5412SJohannes Schauer            "\n");
539fc9c5412SJohannes Schauer 
54063ec54d7SPeter Maydell     /* Calculate column widths. We must always have at least enough space
54163ec54d7SPeter Maydell      * for the column header.
54263ec54d7SPeter Maydell      */
54363ec54d7SPeter Maydell     maxarglen = strlen("Argument");
54463ec54d7SPeter Maydell     maxenvlen = strlen("Env-variable");
545fc9c5412SJohannes Schauer 
546fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
54763ec54d7SPeter Maydell         int arglen = strlen(arginfo->argv);
54863ec54d7SPeter Maydell         if (arginfo->has_arg) {
54963ec54d7SPeter Maydell             arglen += strlen(arginfo->example) + 1;
55063ec54d7SPeter Maydell         }
551fc9c5412SJohannes Schauer         if (strlen(arginfo->env) > maxenvlen) {
552fc9c5412SJohannes Schauer             maxenvlen = strlen(arginfo->env);
553fc9c5412SJohannes Schauer         }
55463ec54d7SPeter Maydell         if (arglen > maxarglen) {
55563ec54d7SPeter Maydell             maxarglen = arglen;
556fc9c5412SJohannes Schauer         }
557fc9c5412SJohannes Schauer     }
558fc9c5412SJohannes Schauer 
55963ec54d7SPeter Maydell     printf("%-*s %-*s Description\n", maxarglen+1, "Argument",
56063ec54d7SPeter Maydell             maxenvlen, "Env-variable");
561fc9c5412SJohannes Schauer 
562fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
563fc9c5412SJohannes Schauer         if (arginfo->has_arg) {
564fc9c5412SJohannes Schauer             printf("-%s %-*s %-*s %s\n", arginfo->argv,
56563ec54d7SPeter Maydell                    (int)(maxarglen - strlen(arginfo->argv) - 1),
56663ec54d7SPeter Maydell                    arginfo->example, maxenvlen, arginfo->env, arginfo->help);
567fc9c5412SJohannes Schauer         } else {
56863ec54d7SPeter Maydell             printf("-%-*s %-*s %s\n", maxarglen, arginfo->argv,
569fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env,
570fc9c5412SJohannes Schauer                     arginfo->help);
571fc9c5412SJohannes Schauer         }
572fc9c5412SJohannes Schauer     }
573fc9c5412SJohannes Schauer 
574fc9c5412SJohannes Schauer     printf("\n"
575fc9c5412SJohannes Schauer            "Defaults:\n"
576fc9c5412SJohannes Schauer            "QEMU_LD_PREFIX  = %s\n"
577989b697dSPeter Maydell            "QEMU_STACK_SIZE = %ld byte\n",
578fc9c5412SJohannes Schauer            interp_prefix,
579989b697dSPeter Maydell            guest_stack_size);
580fc9c5412SJohannes Schauer 
581fc9c5412SJohannes Schauer     printf("\n"
582fc9c5412SJohannes Schauer            "You can use -E and -U options or the QEMU_SET_ENV and\n"
583fc9c5412SJohannes Schauer            "QEMU_UNSET_ENV environment variables to set and unset\n"
584fc9c5412SJohannes Schauer            "environment variables for the target process.\n"
585fc9c5412SJohannes Schauer            "It is possible to provide several variables by separating them\n"
586fc9c5412SJohannes Schauer            "by commas in getsubopt(3) style. Additionally it is possible to\n"
587fc9c5412SJohannes Schauer            "provide the -E and -U options multiple times.\n"
588fc9c5412SJohannes Schauer            "The following lines are equivalent:\n"
589fc9c5412SJohannes Schauer            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
590fc9c5412SJohannes Schauer            "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
591fc9c5412SJohannes Schauer            "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
592fc9c5412SJohannes Schauer            "Note that if you provide several changes to a single variable\n"
593f5048cb7SEric Blake            "the last change will stay in effect.\n"
594f5048cb7SEric Blake            "\n"
595f5048cb7SEric Blake            QEMU_HELP_BOTTOM "\n");
596fc9c5412SJohannes Schauer 
597d03f9c32SMeador Inge     exit(exitcode);
598fc9c5412SJohannes Schauer }
599fc9c5412SJohannes Schauer 
600fc9c5412SJohannes Schauer static int parse_args(int argc, char **argv)
601fc9c5412SJohannes Schauer {
602fc9c5412SJohannes Schauer     const char *r;
603fc9c5412SJohannes Schauer     int optind;
60442644ceeSJim Meyering     const struct qemu_argument *arginfo;
605fc9c5412SJohannes Schauer 
606fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
607fc9c5412SJohannes Schauer         if (arginfo->env == NULL) {
608fc9c5412SJohannes Schauer             continue;
609fc9c5412SJohannes Schauer         }
610fc9c5412SJohannes Schauer 
611fc9c5412SJohannes Schauer         r = getenv(arginfo->env);
612fc9c5412SJohannes Schauer         if (r != NULL) {
613fc9c5412SJohannes Schauer             arginfo->handle_opt(r);
614fc9c5412SJohannes Schauer         }
615fc9c5412SJohannes Schauer     }
616fc9c5412SJohannes Schauer 
617fc9c5412SJohannes Schauer     optind = 1;
618fc9c5412SJohannes Schauer     for (;;) {
619fc9c5412SJohannes Schauer         if (optind >= argc) {
620fc9c5412SJohannes Schauer             break;
621fc9c5412SJohannes Schauer         }
622fc9c5412SJohannes Schauer         r = argv[optind];
623fc9c5412SJohannes Schauer         if (r[0] != '-') {
624fc9c5412SJohannes Schauer             break;
625fc9c5412SJohannes Schauer         }
626fc9c5412SJohannes Schauer         optind++;
627fc9c5412SJohannes Schauer         r++;
628fc9c5412SJohannes Schauer         if (!strcmp(r, "-")) {
629fc9c5412SJohannes Schauer             break;
630fc9c5412SJohannes Schauer         }
631ba02577cSMeador Inge         /* Treat --foo the same as -foo.  */
632ba02577cSMeador Inge         if (r[0] == '-') {
633ba02577cSMeador Inge             r++;
634ba02577cSMeador Inge         }
635fc9c5412SJohannes Schauer 
636fc9c5412SJohannes Schauer         for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
637fc9c5412SJohannes Schauer             if (!strcmp(r, arginfo->argv)) {
6381386d4c0SPeter Maydell                 if (arginfo->has_arg) {
639fc9c5412SJohannes Schauer                     if (optind >= argc) {
640138940bfSMeador Inge                         (void) fprintf(stderr,
641138940bfSMeador Inge                             "qemu: missing argument for option '%s'\n", r);
6424d1275c2SRiku Voipio                         exit(EXIT_FAILURE);
643fc9c5412SJohannes Schauer                     }
644fc9c5412SJohannes Schauer                     arginfo->handle_opt(argv[optind]);
645fc9c5412SJohannes Schauer                     optind++;
6461386d4c0SPeter Maydell                 } else {
6471386d4c0SPeter Maydell                     arginfo->handle_opt(NULL);
648fc9c5412SJohannes Schauer                 }
649fc9c5412SJohannes Schauer                 break;
650fc9c5412SJohannes Schauer             }
651fc9c5412SJohannes Schauer         }
652fc9c5412SJohannes Schauer 
653fc9c5412SJohannes Schauer         /* no option matched the current argv */
654fc9c5412SJohannes Schauer         if (arginfo->handle_opt == NULL) {
655138940bfSMeador Inge             (void) fprintf(stderr, "qemu: unknown option '%s'\n", r);
6564d1275c2SRiku Voipio             exit(EXIT_FAILURE);
657fc9c5412SJohannes Schauer         }
658fc9c5412SJohannes Schauer     }
659fc9c5412SJohannes Schauer 
660fc9c5412SJohannes Schauer     if (optind >= argc) {
661138940bfSMeador Inge         (void) fprintf(stderr, "qemu: no user program specified\n");
6624d1275c2SRiku Voipio         exit(EXIT_FAILURE);
663fc9c5412SJohannes Schauer     }
664fc9c5412SJohannes Schauer 
665fc9c5412SJohannes Schauer     exec_path = argv[optind];
666fc9c5412SJohannes Schauer 
667fc9c5412SJohannes Schauer     return optind;
668fc9c5412SJohannes Schauer }
669fc9c5412SJohannes Schauer 
670902b3d5cSmalc int main(int argc, char **argv, char **envp)
67131e31b8aSbellard {
67201ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
67331e31b8aSbellard     struct image_info info1, *info = &info1;
674edf8e2afSMika Westerberg     struct linux_binprm bprm;
67548e15fc2SNathan Froyd     TaskState *ts;
6769349b4f9SAndreas Färber     CPUArchState *env;
677db6b81d4SAndreas Färber     CPUState *cpu;
678586314f2Sbellard     int optind;
67904a6dfebSaurel32     char **target_environ, **wrk;
6807d8cec95Saurel32     char **target_argv;
6817d8cec95Saurel32     int target_argc;
6827d8cec95Saurel32     int i;
683fd4d81ddSArnaud Patard     int ret;
68403cfd8faSLaurent Vivier     int execfd;
685ff8a8bbcSRichard Henderson     int host_page_size;
6868f67b9c6SRichard Henderson     unsigned long max_reserved_va;
6876e1c0d7bSLaurent Vivier     bool preserve_argv0;
68831e31b8aSbellard 
689f5852efaSChristophe Fergeau     error_init(argv[0]);
690fe4db84dSDaniel P. Berrange     module_call_init(MODULE_INIT_TRACE);
691267f685bSPaolo Bonzini     qemu_init_cpu_list();
692ce008c1fSAndreas Färber     module_call_init(MODULE_INIT_QOM);
693ce008c1fSAndreas Färber 
694ec45bbe5SSaurav Sachidanand     envlist = envlist_create();
69504a6dfebSaurel32 
6967f750efcSAndreas Schwab     /*
6977f750efcSAndreas Schwab      * add current environment into the list
6987f750efcSAndreas Schwab      * envlist_setenv adds to the front of the list; to preserve environ
6997f750efcSAndreas Schwab      * order add from back to front
7007f750efcSAndreas Schwab      */
70104a6dfebSaurel32     for (wrk = environ; *wrk != NULL; wrk++) {
7027f750efcSAndreas Schwab         continue;
7037f750efcSAndreas Schwab     }
7047f750efcSAndreas Schwab     while (wrk != environ) {
7057f750efcSAndreas Schwab         wrk--;
70604a6dfebSaurel32         (void) envlist_setenv(envlist, *wrk);
70704a6dfebSaurel32     }
70804a6dfebSaurel32 
709703e0e89SRichard Henderson     /* Read the stack limit from the kernel.  If it's "unlimited",
710703e0e89SRichard Henderson        then we can do little else besides use the default.  */
711703e0e89SRichard Henderson     {
712703e0e89SRichard Henderson         struct rlimit lim;
713703e0e89SRichard Henderson         if (getrlimit(RLIMIT_STACK, &lim) == 0
71481bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur != RLIM_INFINITY
7150a3346b5SHelge Deller             && lim.rlim_cur == (target_long)lim.rlim_cur
7160a3346b5SHelge Deller             && lim.rlim_cur > guest_stack_size) {
717703e0e89SRichard Henderson             guest_stack_size = lim.rlim_cur;
718703e0e89SRichard Henderson         }
719703e0e89SRichard Henderson     }
720703e0e89SRichard Henderson 
721b1f9be31Sj_mayer     cpu_model = NULL;
722b5ec5ce0Sjohn cooper 
7236533dd6eSLluís Vilanova     qemu_add_opts(&qemu_trace_opts);
724f308f64eSLluís Vilanova     qemu_plugin_add_opts();
7256533dd6eSLluís Vilanova 
726fc9c5412SJohannes Schauer     optind = parse_args(argc, argv);
7274b5dfd82SPeter Maydell 
728b410253fSRichard Henderson     qemu_set_log_filename_flags(last_log_filename,
729b410253fSRichard Henderson                                 last_log_mask | (enable_strace * LOG_STRACE),
730b410253fSRichard Henderson                                 &error_fatal);
7314b25a506SJosh Kunz 
7326533dd6eSLluís Vilanova     if (!trace_init_backends()) {
7336533dd6eSLluís Vilanova         exit(1);
7346533dd6eSLluís Vilanova     }
73592eecfffSPaolo Bonzini     trace_init_file();
7360572f558SPaolo Bonzini     qemu_plugin_load_list(&plugins, &error_fatal);
7376533dd6eSLluís Vilanova 
73831e31b8aSbellard     /* Zero out regs */
73901ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
74031e31b8aSbellard 
74131e31b8aSbellard     /* Zero out image_info */
74231e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
74331e31b8aSbellard 
744edf8e2afSMika Westerberg     memset(&bprm, 0, sizeof (bprm));
745edf8e2afSMika Westerberg 
74674cd30b8Sbellard     /* Scan interp_prefix dir for replacement files. */
74774cd30b8Sbellard     init_paths(interp_prefix);
74874cd30b8Sbellard 
7494a24a758SPeter Maydell     init_qemu_uname_release();
7504a24a758SPeter Maydell 
7516e1c0d7bSLaurent Vivier     /*
7526e1c0d7bSLaurent Vivier      * Manage binfmt-misc open-binary flag
7536e1c0d7bSLaurent Vivier      */
754768fe76eSYunQiang Su     execfd = qemu_getauxval(AT_EXECFD);
755768fe76eSYunQiang Su     if (execfd == 0) {
7569d3019bcSLaurent Vivier         execfd = open(exec_path, O_RDONLY);
757768fe76eSYunQiang Su         if (execfd < 0) {
7589d3019bcSLaurent Vivier             printf("Error while loading %s: %s\n", exec_path, strerror(errno));
759768fe76eSYunQiang Su             _exit(EXIT_FAILURE);
760768fe76eSYunQiang Su         }
761768fe76eSYunQiang Su     }
762768fe76eSYunQiang Su 
763258bec39SHelge Deller     /* Resolve executable file name to full path name */
764258bec39SHelge Deller     if (realpath(exec_path, real_exec_path)) {
765258bec39SHelge Deller         exec_path = real_exec_path;
766258bec39SHelge Deller     }
767258bec39SHelge Deller 
7686e1c0d7bSLaurent Vivier     /*
7696e1c0d7bSLaurent Vivier      * get binfmt_misc flags
7706e1c0d7bSLaurent Vivier      */
7716e1c0d7bSLaurent Vivier     preserve_argv0 = !!(qemu_getauxval(AT_FLAGS) & AT_FLAGS_PRESERVE_ARGV0);
7726e1c0d7bSLaurent Vivier 
7736e1c0d7bSLaurent Vivier     /*
7746e1c0d7bSLaurent Vivier      * Manage binfmt-misc preserve-arg[0] flag
7756e1c0d7bSLaurent Vivier      *    argv[optind]     full path to the binary
7766e1c0d7bSLaurent Vivier      *    argv[optind + 1] original argv[0]
7776e1c0d7bSLaurent Vivier      */
7786e1c0d7bSLaurent Vivier     if (optind + 1 < argc && preserve_argv0) {
7796e1c0d7bSLaurent Vivier         optind++;
7806e1c0d7bSLaurent Vivier     }
7816e1c0d7bSLaurent Vivier 
78246027c07Sbellard     if (cpu_model == NULL) {
783768fe76eSYunQiang Su         cpu_model = cpu_get_model(get_elf_eflags(execfd));
784aaed909aSbellard     }
785c1c8cfe5SEduardo Habkost     cpu_type = parse_cpu_option(cpu_model);
7862278b939SIgor Mammedov 
78713c13397SRichard Henderson     /* init tcg before creating CPUs */
788940e43aaSClaudio Fontana     {
7893cfb0456SPeter Maydell         AccelState *accel = current_accel();
7903cfb0456SPeter Maydell         AccelClass *ac = ACCEL_GET_CLASS(accel);
7912278b939SIgor Mammedov 
792b86f59c7SClaudio Fontana         accel_init_interfaces(ac);
7933cfb0456SPeter Maydell         object_property_set_bool(OBJECT(accel), "one-insn-per-tb",
7943cfb0456SPeter Maydell                                  opt_one_insn_per_tb, &error_abort);
79592242f34SClaudio Fontana         ac->init_machine(NULL);
796940e43aaSClaudio Fontana     }
797ff8a8bbcSRichard Henderson 
798ff8a8bbcSRichard Henderson     /*
799ff8a8bbcSRichard Henderson      * Finalize page size before creating CPUs.
800ff8a8bbcSRichard Henderson      * This will do nothing if !TARGET_PAGE_BITS_VARY.
801ff8a8bbcSRichard Henderson      * The most efficient setting is to match the host.
802ff8a8bbcSRichard Henderson      */
803ff8a8bbcSRichard Henderson     host_page_size = qemu_real_host_page_size();
804ff8a8bbcSRichard Henderson     set_preferred_target_page_bits(ctz32(host_page_size));
805ff8a8bbcSRichard Henderson     finalize_target_page_bits();
806ff8a8bbcSRichard Henderson 
8072278b939SIgor Mammedov     cpu = cpu_create(cpu_type);
808b77af26eSRichard Henderson     env = cpu_env(cpu);
8090ac46af3SAndreas Färber     cpu_reset(cpu);
810db6b81d4SAndreas Färber     thread_cpu = cpu;
81154936004Sbellard 
8128f67b9c6SRichard Henderson     /*
8138f67b9c6SRichard Henderson      * Reserving too much vm space via mmap can run into problems
8148f67b9c6SRichard Henderson      * with rlimits, oom due to page table creation, etc.  We will
8158f67b9c6SRichard Henderson      * still try it, if directed by the command-line option, but
8168f67b9c6SRichard Henderson      * not by default.
8178f67b9c6SRichard Henderson      */
8188f67b9c6SRichard Henderson     max_reserved_va = MAX_RESERVED_VA(cpu);
8198f67b9c6SRichard Henderson     if (reserved_va != 0) {
82013c13397SRichard Henderson         if ((reserved_va + 1) % host_page_size) {
82113c13397SRichard Henderson             char *s = size_to_str(host_page_size);
8222f7828b5SRichard Henderson             fprintf(stderr, "Reserved virtual address not aligned mod %s\n", s);
8232f7828b5SRichard Henderson             g_free(s);
8242f7828b5SRichard Henderson             exit(EXIT_FAILURE);
8252f7828b5SRichard Henderson         }
8268f67b9c6SRichard Henderson         if (max_reserved_va && reserved_va > max_reserved_va) {
8278f67b9c6SRichard Henderson             fprintf(stderr, "Reserved virtual address too big\n");
8288f67b9c6SRichard Henderson             exit(EXIT_FAILURE);
8298f67b9c6SRichard Henderson         }
8308f67b9c6SRichard Henderson     } else if (HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32) {
83195059f9cSRichard Henderson         /* MAX_RESERVED_VA + 1 is a large power of 2, so is aligned. */
83295059f9cSRichard Henderson         reserved_va = max_reserved_va;
8338f67b9c6SRichard Henderson     }
8348f67b9c6SRichard Henderson 
835c8fb5cf9SRichard Henderson     /*
836c8fb5cf9SRichard Henderson      * Temporarily disable
837c8fb5cf9SRichard Henderson      *   "comparison is always false due to limited range of data type"
838c8fb5cf9SRichard Henderson      * due to comparison between (possible) uint64_t and uintptr_t.
839c8fb5cf9SRichard Henderson      */
840c8fb5cf9SRichard Henderson #pragma GCC diagnostic push
841c8fb5cf9SRichard Henderson #pragma GCC diagnostic ignored "-Wtype-limits"
842c8fb5cf9SRichard Henderson 
843c8fb5cf9SRichard Henderson     /*
844c8fb5cf9SRichard Henderson      * Select an initial value for task_unmapped_base that is in range.
845c8fb5cf9SRichard Henderson      */
846c8fb5cf9SRichard Henderson     if (reserved_va) {
847c8fb5cf9SRichard Henderson         if (TASK_UNMAPPED_BASE < reserved_va) {
848c8fb5cf9SRichard Henderson             task_unmapped_base = TASK_UNMAPPED_BASE;
849c8fb5cf9SRichard Henderson         } else {
850c8fb5cf9SRichard Henderson             /* The most common default formula is TASK_SIZE / 3. */
851c8fb5cf9SRichard Henderson             task_unmapped_base = TARGET_PAGE_ALIGN(reserved_va / 3);
852c8fb5cf9SRichard Henderson         }
853c8fb5cf9SRichard Henderson     } else if (TASK_UNMAPPED_BASE < UINTPTR_MAX) {
854c8fb5cf9SRichard Henderson         task_unmapped_base = TASK_UNMAPPED_BASE;
855c8fb5cf9SRichard Henderson     } else {
856c8fb5cf9SRichard Henderson         /* 32-bit host: pick something medium size. */
857c8fb5cf9SRichard Henderson         task_unmapped_base = 0x10000000;
858c8fb5cf9SRichard Henderson     }
859c8fb5cf9SRichard Henderson     mmap_next_start = task_unmapped_base;
860c8fb5cf9SRichard Henderson 
861da2b71faSRichard Henderson     /* Similarly for elf_et_dyn_base. */
862da2b71faSRichard Henderson     if (reserved_va) {
863da2b71faSRichard Henderson         if (ELF_ET_DYN_BASE < reserved_va) {
864da2b71faSRichard Henderson             elf_et_dyn_base = ELF_ET_DYN_BASE;
865da2b71faSRichard Henderson         } else {
866da2b71faSRichard Henderson             /* The most common default formula is TASK_SIZE / 3 * 2. */
867da2b71faSRichard Henderson             elf_et_dyn_base = TARGET_PAGE_ALIGN(reserved_va / 3) * 2;
868da2b71faSRichard Henderson         }
869da2b71faSRichard Henderson     } else if (ELF_ET_DYN_BASE < UINTPTR_MAX) {
870da2b71faSRichard Henderson         elf_et_dyn_base = ELF_ET_DYN_BASE;
871da2b71faSRichard Henderson     } else {
872da2b71faSRichard Henderson         /* 32-bit host: pick something medium size. */
873da2b71faSRichard Henderson         elf_et_dyn_base = 0x18000000;
874da2b71faSRichard Henderson     }
875da2b71faSRichard Henderson 
876c8fb5cf9SRichard Henderson #pragma GCC diagnostic pop
877c8fb5cf9SRichard Henderson 
878a573e9baSRichard Henderson     {
879a573e9baSRichard Henderson         Error *err = NULL;
8805ebdd774SRichard Henderson         if (seed_optarg != NULL) {
881a573e9baSRichard Henderson             qemu_guest_random_seed_main(seed_optarg, &err);
882a573e9baSRichard Henderson         } else {
883a573e9baSRichard Henderson             qcrypto_init(&err);
884a573e9baSRichard Henderson         }
885a573e9baSRichard Henderson         if (err) {
886a573e9baSRichard Henderson             error_reportf_err(err, "cannot initialize crypto: ");
887a573e9baSRichard Henderson             exit(1);
888a573e9baSRichard Henderson         }
889c5e4a5a9SMagnus Reftel     }
890c5e4a5a9SMagnus Reftel 
89104a6dfebSaurel32     target_environ = envlist_to_environ(envlist, NULL);
89204a6dfebSaurel32     envlist_free(envlist);
893b12b6a18Sths 
894379f6698SPaul Brook     /*
895379f6698SPaul Brook      * Read in mmap_min_addr kernel parameter.  This value is used
896379f6698SPaul Brook      * When loading the ELF image to determine whether guest_base
89714f24e14SRichard Henderson      * is needed.  It is also used in mmap_find_vma.
898379f6698SPaul Brook      */
89914f24e14SRichard Henderson     {
900379f6698SPaul Brook         FILE *fp;
901379f6698SPaul Brook 
902379f6698SPaul Brook         if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
903379f6698SPaul Brook             unsigned long tmp;
904c9f80666SRichard Henderson             if (fscanf(fp, "%lu", &tmp) == 1 && tmp != 0) {
90578b79b2cSRichard Henderson                 mmap_min_addr = MAX(tmp, host_page_size);
906c9f80666SRichard Henderson                 qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n",
907c9f80666SRichard Henderson                               mmap_min_addr);
908379f6698SPaul Brook             }
909379f6698SPaul Brook             fclose(fp);
910379f6698SPaul Brook         }
911379f6698SPaul Brook     }
912379f6698SPaul Brook 
9137d8cec95Saurel32     /*
914c9f80666SRichard Henderson      * We prefer to not make NULL pointers accessible to QEMU.
915c9f80666SRichard Henderson      * If we're in a chroot with no /proc, fall back to 1 page.
916c9f80666SRichard Henderson      */
917c9f80666SRichard Henderson     if (mmap_min_addr == 0) {
918ff8a8bbcSRichard Henderson         mmap_min_addr = host_page_size;
919c9f80666SRichard Henderson         qemu_log_mask(CPU_LOG_PAGE,
920c9f80666SRichard Henderson                       "host mmap_min_addr=0x%lx (fallback)\n",
921c9f80666SRichard Henderson                       mmap_min_addr);
922c9f80666SRichard Henderson     }
923c9f80666SRichard Henderson 
924c9f80666SRichard Henderson     /*
9257d8cec95Saurel32      * Prepare copy of argv vector for target.
9267d8cec95Saurel32      */
9277d8cec95Saurel32     target_argc = argc - optind;
9287d8cec95Saurel32     target_argv = calloc(target_argc + 1, sizeof (char *));
9297d8cec95Saurel32     if (target_argv == NULL) {
9307d8cec95Saurel32         (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
9314d1275c2SRiku Voipio         exit(EXIT_FAILURE);
9327d8cec95Saurel32     }
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         }
1018db6b81d4SAndreas Färber         gdb_handlesig(cpu, 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