xref: /qemu/linux-user/main.c (revision 0a3346b5)
131e31b8aSbellard /*
293ac68bcSbellard  *  qemu user main
331e31b8aSbellard  *
468d0f70eSbellard  *  Copyright (c) 2003-2008 Fabrice Bellard
531e31b8aSbellard  *
631e31b8aSbellard  *  This program is free software; you can redistribute it and/or modify
731e31b8aSbellard  *  it under the terms of the GNU General Public License as published by
831e31b8aSbellard  *  the Free Software Foundation; either version 2 of the License, or
931e31b8aSbellard  *  (at your option) any later version.
1031e31b8aSbellard  *
1131e31b8aSbellard  *  This program is distributed in the hope that it will be useful,
1231e31b8aSbellard  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1331e31b8aSbellard  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1431e31b8aSbellard  *  GNU General Public License for more details.
1531e31b8aSbellard  *
1631e31b8aSbellard  *  You should have received a copy of the GNU General Public License
178167ee88SBlue Swirl  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
1831e31b8aSbellard  */
1914a48c1dSMarkus Armbruster 
20d39594e9SPeter Maydell #include "qemu/osdep.h"
2149f95221SMarc-André Lureau #include "qemu/help-texts.h"
22b52713c1SPhilippe Mathieu-Daudé #include "qemu/units.h"
23940e43aaSClaudio Fontana #include "qemu/accel.h"
2467a1de0dSFam Zheng #include "qemu-version.h"
25edf8e2afSMika Westerberg #include <sys/syscall.h>
26703e0e89SRichard Henderson #include <sys/resource.h>
27ee947430SAlex Bennée #include <sys/shm.h>
286e1c0d7bSLaurent Vivier #include <linux/binfmts.h>
2931e31b8aSbellard 
30daa76aa4SMarkus Armbruster #include "qapi/error.h"
313ef693a0Sbellard #include "qemu.h"
323b249d26SPeter Maydell #include "user-internals.h"
33f348b6d1SVeronia Bahaa #include "qemu/path.h"
34dc5e9ac7SMarkus Armbruster #include "qemu/queue.h"
356533dd6eSLluís Vilanova #include "qemu/config-file.h"
36f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
37f5852efaSChristophe Fergeau #include "qemu/error-report.h"
38f348b6d1SVeronia Bahaa #include "qemu/help_option.h"
390b8fa32fSMarkus Armbruster #include "qemu/module.h"
40f308f64eSLluís Vilanova #include "qemu/plugin.h"
4163c91552SPaolo Bonzini #include "exec/exec-all.h"
4285b4fa0cSPeter Maydell #include "exec/gdbstub.h"
43dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg.h"
441de7afc9SPaolo Bonzini #include "qemu/timer.h"
451de7afc9SPaolo Bonzini #include "qemu/envlist.h"
465ebdd774SRichard Henderson #include "qemu/guest-random.h"
47d8fd2954SPaul Brook #include "elf.h"
486533dd6eSLluís Vilanova #include "trace/control.h"
49542ca434SLaurent Vivier #include "target_elf.h"
50cd71c089SLaurent Vivier #include "cpu_loop-common.h"
51a573e9baSRichard Henderson #include "crypto/init.h"
52c093364fSOwen Anderson #include "fd-trans.h"
532113aed6SPeter Maydell #include "signal-common.h"
543ad0a769SPeter Maydell #include "loader.h"
555423e6d3SPeter Maydell #include "user-mmap.h"
5604a6dfebSaurel32 
57e4a4aaa5SRichard Henderson #ifdef CONFIG_SEMIHOSTING
58e4a4aaa5SRichard Henderson #include "semihosting/semihost.h"
59e4a4aaa5SRichard Henderson #endif
60e4a4aaa5SRichard Henderson 
616e1c0d7bSLaurent Vivier #ifndef AT_FLAGS_PRESERVE_ARGV0
626e1c0d7bSLaurent Vivier #define AT_FLAGS_PRESERVE_ARGV0_BIT 0
636e1c0d7bSLaurent Vivier #define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
646e1c0d7bSLaurent Vivier #endif
656e1c0d7bSLaurent Vivier 
66d088d664Saurel32 char *exec_path;
67d088d664Saurel32 
681b530a6dSaurel32 int singlestep;
698cb76755SStefan Weil static const char *argv0;
70fcedd920SAlex Bennée static const char *gdbstub;
718cb76755SStefan Weil static envlist_t *envlist;
7251fb256aSAndreas Färber static const char *cpu_model;
732278b939SIgor Mammedov static const char *cpu_type;
745ebdd774SRichard Henderson static const char *seed_optarg;
75379f6698SPaul Brook unsigned long mmap_min_addr;
765ca870b9SRichard Henderson uintptr_t guest_base;
77e307c192SRichard Henderson bool have_guest_base;
78120a9848SPaolo Bonzini 
79288e65b9SAlexander Graf /*
804b25a506SJosh Kunz  * Used to implement backwards-compatibility for the `-strace`, and
814b25a506SJosh Kunz  * QEMU_STRACE options. Without this, the QEMU_LOG can be overwritten by
824b25a506SJosh Kunz  * -strace, or vice versa.
834b25a506SJosh Kunz  */
844b25a506SJosh Kunz static bool enable_strace;
854b25a506SJosh Kunz 
864b25a506SJosh Kunz /*
874b25a506SJosh Kunz  * The last log mask given by the user in an environment variable or argument.
884b25a506SJosh Kunz  * Used to support command line arguments overriding environment variables.
894b25a506SJosh Kunz  */
904b25a506SJosh Kunz static int last_log_mask;
91b410253fSRichard Henderson static const char *last_log_filename;
924b25a506SJosh Kunz 
934b25a506SJosh Kunz /*
94288e65b9SAlexander Graf  * When running 32-on-64 we should make sure we can fit all of the possible
95288e65b9SAlexander Graf  * guest address space into a contiguous chunk of virtual host memory.
96288e65b9SAlexander Graf  *
97288e65b9SAlexander Graf  * This way we will never overlap with our own libraries or binaries or stack
98288e65b9SAlexander Graf  * or anything else that QEMU maps.
9918e80c55SRichard Henderson  *
10018e80c55SRichard Henderson  * Many cpus reserve the high bit (or more than one for some 64-bit cpus)
10118e80c55SRichard Henderson  * of the address for the kernel.  Some cpus rely on this and user space
10218e80c55SRichard Henderson  * uses the high bit(s) for pointer tagging and the like.  For them, we
10318e80c55SRichard Henderson  * must preserve the expected address space.
104288e65b9SAlexander Graf  */
10518e80c55SRichard Henderson #ifndef MAX_RESERVED_VA
10618e80c55SRichard Henderson # if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
10718e80c55SRichard Henderson #  if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \
10818e80c55SRichard Henderson       (TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
10918e80c55SRichard Henderson /* There are a number of places where we assign reserved_va to a variable
11018e80c55SRichard Henderson    of type abi_ulong and expect it to fit.  Avoid the last page.  */
1118f67b9c6SRichard Henderson #   define MAX_RESERVED_VA(CPU)  (0xfffffffful & TARGET_PAGE_MASK)
112314992b1SAlexander Graf #  else
1138f67b9c6SRichard Henderson #   define MAX_RESERVED_VA(CPU)  (1ul << TARGET_VIRT_ADDR_SPACE_BITS)
114314992b1SAlexander Graf #  endif
115288e65b9SAlexander Graf # else
1168f67b9c6SRichard Henderson #  define MAX_RESERVED_VA(CPU)  0
11718e80c55SRichard Henderson # endif
11818e80c55SRichard Henderson #endif
11918e80c55SRichard Henderson 
12068a1c816SPaul Brook unsigned long reserved_va;
1211b530a6dSaurel32 
122d03f9c32SMeador Inge static void usage(int exitcode);
123fc9c5412SJohannes Schauer 
1247ee2822cSPaolo Bonzini static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
125e586822aSRiku Voipio const char *qemu_uname_release;
126586314f2Sbellard 
1270a3346b5SHelge Deller #if !defined(TARGET_DEFAULT_STACK_SIZE)
1289de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
1299de5e440Sbellard    we allocate a bigger stack. Need a better solution, for example
1309de5e440Sbellard    by remapping the process stack directly at the right place */
1310a3346b5SHelge Deller #define TARGET_DEFAULT_STACK_SIZE	8 * 1024 * 1024UL
1320a3346b5SHelge Deller #endif
1330a3346b5SHelge Deller 
1340a3346b5SHelge Deller unsigned long guest_stack_size = TARGET_DEFAULT_STACK_SIZE;
13531e31b8aSbellard 
136d5975363Spbrook /***********************************************************/
137d5975363Spbrook /* Helper routines for implementing atomic operations.  */
138d5975363Spbrook 
139d5975363Spbrook /* Make sure everything is in a consistent state for calling fork().  */
140d5975363Spbrook void fork_start(void)
141d5975363Spbrook {
14206065c45SPeter Maydell     start_exclusive();
143d032d1b4SRiku Voipio     mmap_fork_start();
144024949caSPeter Maydell     cpu_list_lock();
145d5975363Spbrook }
146d5975363Spbrook 
147d5975363Spbrook void fork_end(int child)
148d5975363Spbrook {
149d032d1b4SRiku Voipio     mmap_fork_end(child);
150d5975363Spbrook     if (child) {
151bdc44640SAndreas Färber         CPUState *cpu, *next_cpu;
152d5975363Spbrook         /* Child processes created by fork() only have a single thread.
153d5975363Spbrook            Discard information about the parent threads.  */
154bdc44640SAndreas Färber         CPU_FOREACH_SAFE(cpu, next_cpu) {
155bdc44640SAndreas Färber             if (cpu != thread_cpu) {
156068a5ea0SEmilio G. Cota                 QTAILQ_REMOVE_RCU(&cpus, cpu, node);
157bdc44640SAndreas Färber             }
158bdc44640SAndreas Färber         }
159267f685bSPaolo Bonzini         qemu_init_cpu_list();
160f7ec7f7bSPeter Crosthwaite         gdbserver_fork(thread_cpu);
16106065c45SPeter Maydell         /* qemu_init_cpu_list() takes care of reinitializing the
16206065c45SPeter Maydell          * exclusive state, so we don't need to end_exclusive() here.
16306065c45SPeter Maydell          */
164d5975363Spbrook     } else {
165267f685bSPaolo Bonzini         cpu_list_unlock();
16606065c45SPeter Maydell         end_exclusive();
167d5975363Spbrook     }
168d5975363Spbrook }
169d5975363Spbrook 
170b44316fbSPeter Maydell __thread CPUState *thread_cpu;
17159faf6d6Sbellard 
172178f9429SSergey Fedorov bool qemu_cpu_is_self(CPUState *cpu)
173178f9429SSergey Fedorov {
174178f9429SSergey Fedorov     return thread_cpu == cpu;
175178f9429SSergey Fedorov }
176178f9429SSergey Fedorov 
177178f9429SSergey Fedorov void qemu_cpu_kick(CPUState *cpu)
178178f9429SSergey Fedorov {
179178f9429SSergey Fedorov     cpu_exit(cpu);
180178f9429SSergey Fedorov }
181178f9429SSergey Fedorov 
182edf8e2afSMika Westerberg void task_settid(TaskState *ts)
183edf8e2afSMika Westerberg {
184edf8e2afSMika Westerberg     if (ts->ts_tid == 0) {
185edf8e2afSMika Westerberg         ts->ts_tid = (pid_t)syscall(SYS_gettid);
186edf8e2afSMika Westerberg     }
187edf8e2afSMika Westerberg }
188edf8e2afSMika Westerberg 
189edf8e2afSMika Westerberg void stop_all_tasks(void)
190edf8e2afSMika Westerberg {
191edf8e2afSMika Westerberg     /*
192edf8e2afSMika Westerberg      * We trust that when using NPTL, start_exclusive()
193edf8e2afSMika Westerberg      * handles thread stopping correctly.
194edf8e2afSMika Westerberg      */
195edf8e2afSMika Westerberg     start_exclusive();
196edf8e2afSMika Westerberg }
197edf8e2afSMika Westerberg 
198c3a92833Spbrook /* Assumes contents are already zeroed.  */
199624f7979Spbrook void init_task_state(TaskState *ts)
200624f7979Spbrook {
201eb33cdaeSCameron Esfahani     long ticks_per_sec;
202eb33cdaeSCameron Esfahani     struct timespec bt;
203eb33cdaeSCameron Esfahani 
204624f7979Spbrook     ts->used = 1;
2055bfce0b7SPeter Maydell     ts->sigaltstack_used = (struct target_sigaltstack) {
2065bfce0b7SPeter Maydell         .ss_sp = 0,
2075bfce0b7SPeter Maydell         .ss_size = 0,
2085bfce0b7SPeter Maydell         .ss_flags = TARGET_SS_DISABLE,
2095bfce0b7SPeter Maydell     };
210eb33cdaeSCameron Esfahani 
211eb33cdaeSCameron Esfahani     /* Capture task start time relative to system boot */
212eb33cdaeSCameron Esfahani 
213eb33cdaeSCameron Esfahani     ticks_per_sec = sysconf(_SC_CLK_TCK);
214eb33cdaeSCameron Esfahani 
215eb33cdaeSCameron Esfahani     if ((ticks_per_sec > 0) && !clock_gettime(CLOCK_BOOTTIME, &bt)) {
216eb33cdaeSCameron Esfahani         /* start_boottime is expressed in clock ticks */
217eb33cdaeSCameron Esfahani         ts->start_boottime = bt.tv_sec * (uint64_t) ticks_per_sec;
218eb33cdaeSCameron Esfahani         ts->start_boottime += bt.tv_nsec * (uint64_t) ticks_per_sec /
219eb33cdaeSCameron Esfahani                               NANOSECONDS_PER_SECOND;
220eb33cdaeSCameron Esfahani     }
221624f7979Spbrook }
2229de5e440Sbellard 
22330ba0ee5SAndreas Färber CPUArchState *cpu_copy(CPUArchState *env)
22430ba0ee5SAndreas Färber {
22529a0af61SRichard Henderson     CPUState *cpu = env_cpu(env);
2262278b939SIgor Mammedov     CPUState *new_cpu = cpu_create(cpu_type);
22761c7480fSLeon Alrae     CPUArchState *new_env = new_cpu->env_ptr;
22830ba0ee5SAndreas Färber     CPUBreakpoint *bp;
22930ba0ee5SAndreas Färber 
23030ba0ee5SAndreas Färber     /* Reset non arch specific state */
23175a34036SAndreas Färber     cpu_reset(new_cpu);
23230ba0ee5SAndreas Färber 
2336cc9d67cSRichard Henderson     new_cpu->tcg_cflags = cpu->tcg_cflags;
23430ba0ee5SAndreas Färber     memcpy(new_env, env, sizeof(CPUArchState));
23530ba0ee5SAndreas Färber 
23630ba0ee5SAndreas Färber     /* Clone all break/watchpoints.
23730ba0ee5SAndreas Färber        Note: Once we support ptrace with hw-debug register access, make sure
23830ba0ee5SAndreas Färber        BP_CPU break/watchpoints are handled correctly on clone. */
2391d085f6cSThierry Bultel     QTAILQ_INIT(&new_cpu->breakpoints);
240f0c3c505SAndreas Färber     QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
241b3310ab3SAndreas Färber         cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
24230ba0ee5SAndreas Färber     }
24330ba0ee5SAndreas Färber 
24430ba0ee5SAndreas Färber     return new_env;
24530ba0ee5SAndreas Färber }
24630ba0ee5SAndreas Färber 
247fc9c5412SJohannes Schauer static void handle_arg_help(const char *arg)
248fc9c5412SJohannes Schauer {
2494d1275c2SRiku Voipio     usage(EXIT_SUCCESS);
250fc9c5412SJohannes Schauer }
251fc9c5412SJohannes Schauer 
252fc9c5412SJohannes Schauer static void handle_arg_log(const char *arg)
253fc9c5412SJohannes Schauer {
2544b25a506SJosh Kunz     last_log_mask = qemu_str_to_log_mask(arg);
2554b25a506SJosh Kunz     if (!last_log_mask) {
25659a6fa6eSPeter Maydell         qemu_print_log_usage(stdout);
2574d1275c2SRiku Voipio         exit(EXIT_FAILURE);
258fc9c5412SJohannes Schauer     }
259fc9c5412SJohannes Schauer }
260fc9c5412SJohannes Schauer 
2618423fa90SAlex Bennée static void handle_arg_dfilter(const char *arg)
2628423fa90SAlex Bennée {
2637f4341e8SAlex Bennée     qemu_set_dfilter_ranges(arg, &error_fatal);
2648423fa90SAlex Bennée }
2658423fa90SAlex Bennée 
26650171d42S陳韋任 static void handle_arg_log_filename(const char *arg)
26750171d42S陳韋任 {
268b410253fSRichard Henderson     last_log_filename = arg;
26950171d42S陳韋任 }
27050171d42S陳韋任 
271fc9c5412SJohannes Schauer static void handle_arg_set_env(const char *arg)
272fc9c5412SJohannes Schauer {
273fc9c5412SJohannes Schauer     char *r, *p, *token;
274fc9c5412SJohannes Schauer     r = p = strdup(arg);
275fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
276fc9c5412SJohannes Schauer         if (envlist_setenv(envlist, token) != 0) {
2774d1275c2SRiku Voipio             usage(EXIT_FAILURE);
278fc9c5412SJohannes Schauer         }
279fc9c5412SJohannes Schauer     }
280fc9c5412SJohannes Schauer     free(r);
281fc9c5412SJohannes Schauer }
282fc9c5412SJohannes Schauer 
283fc9c5412SJohannes Schauer static void handle_arg_unset_env(const char *arg)
284fc9c5412SJohannes Schauer {
285fc9c5412SJohannes Schauer     char *r, *p, *token;
286fc9c5412SJohannes Schauer     r = p = strdup(arg);
287fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
288fc9c5412SJohannes Schauer         if (envlist_unsetenv(envlist, token) != 0) {
2894d1275c2SRiku Voipio             usage(EXIT_FAILURE);
290fc9c5412SJohannes Schauer         }
291fc9c5412SJohannes Schauer     }
292fc9c5412SJohannes Schauer     free(r);
293fc9c5412SJohannes Schauer }
294fc9c5412SJohannes Schauer 
295fc9c5412SJohannes Schauer static void handle_arg_argv0(const char *arg)
296fc9c5412SJohannes Schauer {
297fc9c5412SJohannes Schauer     argv0 = strdup(arg);
298fc9c5412SJohannes Schauer }
299fc9c5412SJohannes Schauer 
300fc9c5412SJohannes Schauer static void handle_arg_stack_size(const char *arg)
301fc9c5412SJohannes Schauer {
302fc9c5412SJohannes Schauer     char *p;
303fc9c5412SJohannes Schauer     guest_stack_size = strtoul(arg, &p, 0);
304fc9c5412SJohannes Schauer     if (guest_stack_size == 0) {
3054d1275c2SRiku Voipio         usage(EXIT_FAILURE);
306fc9c5412SJohannes Schauer     }
307fc9c5412SJohannes Schauer 
308fc9c5412SJohannes Schauer     if (*p == 'M') {
309b52713c1SPhilippe Mathieu-Daudé         guest_stack_size *= MiB;
310fc9c5412SJohannes Schauer     } else if (*p == 'k' || *p == 'K') {
311b52713c1SPhilippe Mathieu-Daudé         guest_stack_size *= KiB;
312fc9c5412SJohannes Schauer     }
313fc9c5412SJohannes Schauer }
314fc9c5412SJohannes Schauer 
315fc9c5412SJohannes Schauer static void handle_arg_ld_prefix(const char *arg)
316fc9c5412SJohannes Schauer {
317fc9c5412SJohannes Schauer     interp_prefix = strdup(arg);
318fc9c5412SJohannes Schauer }
319fc9c5412SJohannes Schauer 
320fc9c5412SJohannes Schauer static void handle_arg_pagesize(const char *arg)
321fc9c5412SJohannes Schauer {
322fc9c5412SJohannes Schauer     qemu_host_page_size = atoi(arg);
323fc9c5412SJohannes Schauer     if (qemu_host_page_size == 0 ||
324fc9c5412SJohannes Schauer         (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
325fc9c5412SJohannes Schauer         fprintf(stderr, "page size must be a power of two\n");
3264d1275c2SRiku Voipio         exit(EXIT_FAILURE);
327fc9c5412SJohannes Schauer     }
328fc9c5412SJohannes Schauer }
329fc9c5412SJohannes Schauer 
3305ebdd774SRichard Henderson static void handle_arg_seed(const char *arg)
331c5e4a5a9SMagnus Reftel {
3325ebdd774SRichard Henderson     seed_optarg = arg;
333c5e4a5a9SMagnus Reftel }
334c5e4a5a9SMagnus Reftel 
335fc9c5412SJohannes Schauer static void handle_arg_gdb(const char *arg)
336fc9c5412SJohannes Schauer {
337fcedd920SAlex Bennée     gdbstub = g_strdup(arg);
338fc9c5412SJohannes Schauer }
339fc9c5412SJohannes Schauer 
340fc9c5412SJohannes Schauer static void handle_arg_uname(const char *arg)
341fc9c5412SJohannes Schauer {
342fc9c5412SJohannes Schauer     qemu_uname_release = strdup(arg);
343fc9c5412SJohannes Schauer }
344fc9c5412SJohannes Schauer 
345fc9c5412SJohannes Schauer static void handle_arg_cpu(const char *arg)
346fc9c5412SJohannes Schauer {
347fc9c5412SJohannes Schauer     cpu_model = strdup(arg);
348c8057f95SPeter Maydell     if (cpu_model == NULL || is_help_option(cpu_model)) {
349fc9c5412SJohannes Schauer         /* XXX: implement xxx_cpu_list for targets that still miss it */
350e916cbf8SPeter Maydell #if defined(cpu_list)
3510442428aSMarkus Armbruster         cpu_list();
352fc9c5412SJohannes Schauer #endif
3534d1275c2SRiku Voipio         exit(EXIT_FAILURE);
354fc9c5412SJohannes Schauer     }
355fc9c5412SJohannes Schauer }
356fc9c5412SJohannes Schauer 
357fc9c5412SJohannes Schauer static void handle_arg_guest_base(const char *arg)
358fc9c5412SJohannes Schauer {
359fc9c5412SJohannes Schauer     guest_base = strtol(arg, NULL, 0);
360e307c192SRichard Henderson     have_guest_base = true;
361fc9c5412SJohannes Schauer }
362fc9c5412SJohannes Schauer 
363fc9c5412SJohannes Schauer static void handle_arg_reserved_va(const char *arg)
364fc9c5412SJohannes Schauer {
365fc9c5412SJohannes Schauer     char *p;
366fc9c5412SJohannes Schauer     int shift = 0;
367fc9c5412SJohannes Schauer     reserved_va = strtoul(arg, &p, 0);
368fc9c5412SJohannes Schauer     switch (*p) {
369fc9c5412SJohannes Schauer     case 'k':
370fc9c5412SJohannes Schauer     case 'K':
371fc9c5412SJohannes Schauer         shift = 10;
372fc9c5412SJohannes Schauer         break;
373fc9c5412SJohannes Schauer     case 'M':
374fc9c5412SJohannes Schauer         shift = 20;
375fc9c5412SJohannes Schauer         break;
376fc9c5412SJohannes Schauer     case 'G':
377fc9c5412SJohannes Schauer         shift = 30;
378fc9c5412SJohannes Schauer         break;
379fc9c5412SJohannes Schauer     }
380fc9c5412SJohannes Schauer     if (shift) {
381fc9c5412SJohannes Schauer         unsigned long unshifted = reserved_va;
382fc9c5412SJohannes Schauer         p++;
383fc9c5412SJohannes Schauer         reserved_va <<= shift;
3848f67b9c6SRichard Henderson         if (reserved_va >> shift != unshifted) {
385fc9c5412SJohannes Schauer             fprintf(stderr, "Reserved virtual address too big\n");
3864d1275c2SRiku Voipio             exit(EXIT_FAILURE);
387fc9c5412SJohannes Schauer         }
388fc9c5412SJohannes Schauer     }
389fc9c5412SJohannes Schauer     if (*p) {
390fc9c5412SJohannes Schauer         fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
3914d1275c2SRiku Voipio         exit(EXIT_FAILURE);
392fc9c5412SJohannes Schauer     }
393fc9c5412SJohannes Schauer }
394fc9c5412SJohannes Schauer 
395fc9c5412SJohannes Schauer static void handle_arg_singlestep(const char *arg)
396fc9c5412SJohannes Schauer {
397fc9c5412SJohannes Schauer     singlestep = 1;
398fc9c5412SJohannes Schauer }
399fc9c5412SJohannes Schauer 
400fc9c5412SJohannes Schauer static void handle_arg_strace(const char *arg)
401fc9c5412SJohannes Schauer {
4024b25a506SJosh Kunz     enable_strace = true;
403fc9c5412SJohannes Schauer }
404fc9c5412SJohannes Schauer 
405fc9c5412SJohannes Schauer static void handle_arg_version(const char *arg)
406fc9c5412SJohannes Schauer {
4077e563bfbSThomas Huth     printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
4080781dd6eSThomas Huth            "\n" QEMU_COPYRIGHT "\n");
4094d1275c2SRiku Voipio     exit(EXIT_SUCCESS);
410fc9c5412SJohannes Schauer }
411fc9c5412SJohannes Schauer 
4126533dd6eSLluís Vilanova static void handle_arg_trace(const char *arg)
4136533dd6eSLluís Vilanova {
41492eecfffSPaolo Bonzini     trace_opt_parse(arg);
4156533dd6eSLluís Vilanova }
4166533dd6eSLluís Vilanova 
417130ea832SMax Filippov #if defined(TARGET_XTENSA)
418130ea832SMax Filippov static void handle_arg_abi_call0(const char *arg)
419130ea832SMax Filippov {
420130ea832SMax Filippov     xtensa_set_abi_call0();
421130ea832SMax Filippov }
422130ea832SMax Filippov #endif
423130ea832SMax Filippov 
424f308f64eSLluís Vilanova static QemuPluginList plugins = QTAILQ_HEAD_INITIALIZER(plugins);
425f308f64eSLluís Vilanova 
426f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
427f308f64eSLluís Vilanova static void handle_arg_plugin(const char *arg)
428f308f64eSLluís Vilanova {
429f308f64eSLluís Vilanova     qemu_plugin_opt_parse(arg, &plugins);
430f308f64eSLluís Vilanova }
431f308f64eSLluís Vilanova #endif
432f308f64eSLluís Vilanova 
433fc9c5412SJohannes Schauer struct qemu_argument {
434fc9c5412SJohannes Schauer     const char *argv;
435fc9c5412SJohannes Schauer     const char *env;
436fc9c5412SJohannes Schauer     bool has_arg;
437fc9c5412SJohannes Schauer     void (*handle_opt)(const char *arg);
438fc9c5412SJohannes Schauer     const char *example;
439fc9c5412SJohannes Schauer     const char *help;
440fc9c5412SJohannes Schauer };
441fc9c5412SJohannes Schauer 
44242644ceeSJim Meyering static const struct qemu_argument arg_table[] = {
443fc9c5412SJohannes Schauer     {"h",          "",                 false, handle_arg_help,
444fc9c5412SJohannes Schauer      "",           "print this help"},
445daaf8c8eSMeador Inge     {"help",       "",                 false, handle_arg_help,
446daaf8c8eSMeador Inge      "",           ""},
447fc9c5412SJohannes Schauer     {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
448fc9c5412SJohannes Schauer      "port",       "wait gdb connection to 'port'"},
449fc9c5412SJohannes Schauer     {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
450fc9c5412SJohannes Schauer      "path",       "set the elf interpreter prefix to 'path'"},
451fc9c5412SJohannes Schauer     {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
452fc9c5412SJohannes Schauer      "size",       "set the stack size to 'size' bytes"},
453fc9c5412SJohannes Schauer     {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
454c8057f95SPeter Maydell      "model",      "select CPU (-cpu help for list)"},
455fc9c5412SJohannes Schauer     {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
456fc9c5412SJohannes Schauer      "var=value",  "sets targets environment variable (see below)"},
457fc9c5412SJohannes Schauer     {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
458fc9c5412SJohannes Schauer      "var",        "unsets targets environment variable (see below)"},
459fc9c5412SJohannes Schauer     {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
460fc9c5412SJohannes Schauer      "argv0",      "forces target process argv[0] to be 'argv0'"},
461fc9c5412SJohannes Schauer     {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
462fc9c5412SJohannes Schauer      "uname",      "set qemu uname release string to 'uname'"},
463fc9c5412SJohannes Schauer     {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
464fc9c5412SJohannes Schauer      "address",    "set guest_base address to 'address'"},
465fc9c5412SJohannes Schauer     {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
466fc9c5412SJohannes Schauer      "size",       "reserve 'size' bytes for guest virtual address space"},
467fc9c5412SJohannes Schauer     {"d",          "QEMU_LOG",         true,  handle_arg_log,
468989b697dSPeter Maydell      "item[,...]", "enable logging of specified items "
469989b697dSPeter Maydell      "(use '-d help' for a list of items)"},
4708423fa90SAlex Bennée     {"dfilter",    "QEMU_DFILTER",     true,  handle_arg_dfilter,
4718423fa90SAlex Bennée      "range[,...]","filter logging based on address range"},
47250171d42S陳韋任     {"D",          "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
473989b697dSPeter Maydell      "logfile",     "write logs to 'logfile' (default stderr)"},
474fc9c5412SJohannes Schauer     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
475fc9c5412SJohannes Schauer      "pagesize",   "set the host page size to 'pagesize'"},
476fc9c5412SJohannes Schauer     {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
477fc9c5412SJohannes Schauer      "",           "run in singlestep mode"},
478fc9c5412SJohannes Schauer     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
479fc9c5412SJohannes Schauer      "",           "log system calls"},
4805ebdd774SRichard Henderson     {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_seed,
481c5e4a5a9SMagnus Reftel      "",           "Seed for pseudo-random number generator"},
4826533dd6eSLluís Vilanova     {"trace",      "QEMU_TRACE",       true,  handle_arg_trace,
4836533dd6eSLluís Vilanova      "",           "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
484f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
485f308f64eSLluís Vilanova     {"plugin",     "QEMU_PLUGIN",      true,  handle_arg_plugin,
4863a445acbSMahmoud Mandour      "",           "[file=]<file>[,<argname>=<argvalue>]"},
487f308f64eSLluís Vilanova #endif
488fc9c5412SJohannes Schauer     {"version",    "QEMU_VERSION",     false, handle_arg_version,
4891386d4c0SPeter Maydell      "",           "display version information and exit"},
490130ea832SMax Filippov #if defined(TARGET_XTENSA)
491130ea832SMax Filippov     {"xtensa-abi-call0", "QEMU_XTENSA_ABI_CALL0", false, handle_arg_abi_call0,
492130ea832SMax Filippov      "",           "assume CALL0 Xtensa ABI"},
493130ea832SMax Filippov #endif
494fc9c5412SJohannes Schauer     {NULL, NULL, false, NULL, NULL, NULL}
495fc9c5412SJohannes Schauer };
496fc9c5412SJohannes Schauer 
497d03f9c32SMeador Inge static void usage(int exitcode)
498fc9c5412SJohannes Schauer {
49942644ceeSJim Meyering     const struct qemu_argument *arginfo;
500fc9c5412SJohannes Schauer     int maxarglen;
501fc9c5412SJohannes Schauer     int maxenvlen;
502fc9c5412SJohannes Schauer 
5032e59915dSPaolo Bonzini     printf("usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
5042e59915dSPaolo Bonzini            "Linux CPU emulator (compiled for " TARGET_NAME " emulation)\n"
505fc9c5412SJohannes Schauer            "\n"
506fc9c5412SJohannes Schauer            "Options and associated environment variables:\n"
507fc9c5412SJohannes Schauer            "\n");
508fc9c5412SJohannes Schauer 
50963ec54d7SPeter Maydell     /* Calculate column widths. We must always have at least enough space
51063ec54d7SPeter Maydell      * for the column header.
51163ec54d7SPeter Maydell      */
51263ec54d7SPeter Maydell     maxarglen = strlen("Argument");
51363ec54d7SPeter Maydell     maxenvlen = strlen("Env-variable");
514fc9c5412SJohannes Schauer 
515fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
51663ec54d7SPeter Maydell         int arglen = strlen(arginfo->argv);
51763ec54d7SPeter Maydell         if (arginfo->has_arg) {
51863ec54d7SPeter Maydell             arglen += strlen(arginfo->example) + 1;
51963ec54d7SPeter Maydell         }
520fc9c5412SJohannes Schauer         if (strlen(arginfo->env) > maxenvlen) {
521fc9c5412SJohannes Schauer             maxenvlen = strlen(arginfo->env);
522fc9c5412SJohannes Schauer         }
52363ec54d7SPeter Maydell         if (arglen > maxarglen) {
52463ec54d7SPeter Maydell             maxarglen = arglen;
525fc9c5412SJohannes Schauer         }
526fc9c5412SJohannes Schauer     }
527fc9c5412SJohannes Schauer 
52863ec54d7SPeter Maydell     printf("%-*s %-*s Description\n", maxarglen+1, "Argument",
52963ec54d7SPeter Maydell             maxenvlen, "Env-variable");
530fc9c5412SJohannes Schauer 
531fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
532fc9c5412SJohannes Schauer         if (arginfo->has_arg) {
533fc9c5412SJohannes Schauer             printf("-%s %-*s %-*s %s\n", arginfo->argv,
53463ec54d7SPeter Maydell                    (int)(maxarglen - strlen(arginfo->argv) - 1),
53563ec54d7SPeter Maydell                    arginfo->example, maxenvlen, arginfo->env, arginfo->help);
536fc9c5412SJohannes Schauer         } else {
53763ec54d7SPeter Maydell             printf("-%-*s %-*s %s\n", maxarglen, arginfo->argv,
538fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env,
539fc9c5412SJohannes Schauer                     arginfo->help);
540fc9c5412SJohannes Schauer         }
541fc9c5412SJohannes Schauer     }
542fc9c5412SJohannes Schauer 
543fc9c5412SJohannes Schauer     printf("\n"
544fc9c5412SJohannes Schauer            "Defaults:\n"
545fc9c5412SJohannes Schauer            "QEMU_LD_PREFIX  = %s\n"
546989b697dSPeter Maydell            "QEMU_STACK_SIZE = %ld byte\n",
547fc9c5412SJohannes Schauer            interp_prefix,
548989b697dSPeter Maydell            guest_stack_size);
549fc9c5412SJohannes Schauer 
550fc9c5412SJohannes Schauer     printf("\n"
551fc9c5412SJohannes Schauer            "You can use -E and -U options or the QEMU_SET_ENV and\n"
552fc9c5412SJohannes Schauer            "QEMU_UNSET_ENV environment variables to set and unset\n"
553fc9c5412SJohannes Schauer            "environment variables for the target process.\n"
554fc9c5412SJohannes Schauer            "It is possible to provide several variables by separating them\n"
555fc9c5412SJohannes Schauer            "by commas in getsubopt(3) style. Additionally it is possible to\n"
556fc9c5412SJohannes Schauer            "provide the -E and -U options multiple times.\n"
557fc9c5412SJohannes Schauer            "The following lines are equivalent:\n"
558fc9c5412SJohannes Schauer            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
559fc9c5412SJohannes Schauer            "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
560fc9c5412SJohannes Schauer            "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
561fc9c5412SJohannes Schauer            "Note that if you provide several changes to a single variable\n"
562f5048cb7SEric Blake            "the last change will stay in effect.\n"
563f5048cb7SEric Blake            "\n"
564f5048cb7SEric Blake            QEMU_HELP_BOTTOM "\n");
565fc9c5412SJohannes Schauer 
566d03f9c32SMeador Inge     exit(exitcode);
567fc9c5412SJohannes Schauer }
568fc9c5412SJohannes Schauer 
569fc9c5412SJohannes Schauer static int parse_args(int argc, char **argv)
570fc9c5412SJohannes Schauer {
571fc9c5412SJohannes Schauer     const char *r;
572fc9c5412SJohannes Schauer     int optind;
57342644ceeSJim Meyering     const struct qemu_argument *arginfo;
574fc9c5412SJohannes Schauer 
575fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
576fc9c5412SJohannes Schauer         if (arginfo->env == NULL) {
577fc9c5412SJohannes Schauer             continue;
578fc9c5412SJohannes Schauer         }
579fc9c5412SJohannes Schauer 
580fc9c5412SJohannes Schauer         r = getenv(arginfo->env);
581fc9c5412SJohannes Schauer         if (r != NULL) {
582fc9c5412SJohannes Schauer             arginfo->handle_opt(r);
583fc9c5412SJohannes Schauer         }
584fc9c5412SJohannes Schauer     }
585fc9c5412SJohannes Schauer 
586fc9c5412SJohannes Schauer     optind = 1;
587fc9c5412SJohannes Schauer     for (;;) {
588fc9c5412SJohannes Schauer         if (optind >= argc) {
589fc9c5412SJohannes Schauer             break;
590fc9c5412SJohannes Schauer         }
591fc9c5412SJohannes Schauer         r = argv[optind];
592fc9c5412SJohannes Schauer         if (r[0] != '-') {
593fc9c5412SJohannes Schauer             break;
594fc9c5412SJohannes Schauer         }
595fc9c5412SJohannes Schauer         optind++;
596fc9c5412SJohannes Schauer         r++;
597fc9c5412SJohannes Schauer         if (!strcmp(r, "-")) {
598fc9c5412SJohannes Schauer             break;
599fc9c5412SJohannes Schauer         }
600ba02577cSMeador Inge         /* Treat --foo the same as -foo.  */
601ba02577cSMeador Inge         if (r[0] == '-') {
602ba02577cSMeador Inge             r++;
603ba02577cSMeador Inge         }
604fc9c5412SJohannes Schauer 
605fc9c5412SJohannes Schauer         for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
606fc9c5412SJohannes Schauer             if (!strcmp(r, arginfo->argv)) {
6071386d4c0SPeter Maydell                 if (arginfo->has_arg) {
608fc9c5412SJohannes Schauer                     if (optind >= argc) {
609138940bfSMeador Inge                         (void) fprintf(stderr,
610138940bfSMeador Inge                             "qemu: missing argument for option '%s'\n", r);
6114d1275c2SRiku Voipio                         exit(EXIT_FAILURE);
612fc9c5412SJohannes Schauer                     }
613fc9c5412SJohannes Schauer                     arginfo->handle_opt(argv[optind]);
614fc9c5412SJohannes Schauer                     optind++;
6151386d4c0SPeter Maydell                 } else {
6161386d4c0SPeter Maydell                     arginfo->handle_opt(NULL);
617fc9c5412SJohannes Schauer                 }
618fc9c5412SJohannes Schauer                 break;
619fc9c5412SJohannes Schauer             }
620fc9c5412SJohannes Schauer         }
621fc9c5412SJohannes Schauer 
622fc9c5412SJohannes Schauer         /* no option matched the current argv */
623fc9c5412SJohannes Schauer         if (arginfo->handle_opt == NULL) {
624138940bfSMeador Inge             (void) fprintf(stderr, "qemu: unknown option '%s'\n", r);
6254d1275c2SRiku Voipio             exit(EXIT_FAILURE);
626fc9c5412SJohannes Schauer         }
627fc9c5412SJohannes Schauer     }
628fc9c5412SJohannes Schauer 
629fc9c5412SJohannes Schauer     if (optind >= argc) {
630138940bfSMeador Inge         (void) fprintf(stderr, "qemu: no user program specified\n");
6314d1275c2SRiku Voipio         exit(EXIT_FAILURE);
632fc9c5412SJohannes Schauer     }
633fc9c5412SJohannes Schauer 
634fc9c5412SJohannes Schauer     exec_path = argv[optind];
635fc9c5412SJohannes Schauer 
636fc9c5412SJohannes Schauer     return optind;
637fc9c5412SJohannes Schauer }
638fc9c5412SJohannes Schauer 
639902b3d5cSmalc int main(int argc, char **argv, char **envp)
64031e31b8aSbellard {
64101ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
64231e31b8aSbellard     struct image_info info1, *info = &info1;
643edf8e2afSMika Westerberg     struct linux_binprm bprm;
64448e15fc2SNathan Froyd     TaskState *ts;
6459349b4f9SAndreas Färber     CPUArchState *env;
646db6b81d4SAndreas Färber     CPUState *cpu;
647586314f2Sbellard     int optind;
64804a6dfebSaurel32     char **target_environ, **wrk;
6497d8cec95Saurel32     char **target_argv;
6507d8cec95Saurel32     int target_argc;
6517d8cec95Saurel32     int i;
652fd4d81ddSArnaud Patard     int ret;
65303cfd8faSLaurent Vivier     int execfd;
6548f67b9c6SRichard Henderson     unsigned long max_reserved_va;
6556e1c0d7bSLaurent Vivier     bool preserve_argv0;
65631e31b8aSbellard 
657f5852efaSChristophe Fergeau     error_init(argv[0]);
658fe4db84dSDaniel P. Berrange     module_call_init(MODULE_INIT_TRACE);
659267f685bSPaolo Bonzini     qemu_init_cpu_list();
660ce008c1fSAndreas Färber     module_call_init(MODULE_INIT_QOM);
661ce008c1fSAndreas Färber 
662ec45bbe5SSaurav Sachidanand     envlist = envlist_create();
66304a6dfebSaurel32 
66404a6dfebSaurel32     /* add current environment into the list */
66504a6dfebSaurel32     for (wrk = environ; *wrk != NULL; wrk++) {
66604a6dfebSaurel32         (void) envlist_setenv(envlist, *wrk);
66704a6dfebSaurel32     }
66804a6dfebSaurel32 
669703e0e89SRichard Henderson     /* Read the stack limit from the kernel.  If it's "unlimited",
670703e0e89SRichard Henderson        then we can do little else besides use the default.  */
671703e0e89SRichard Henderson     {
672703e0e89SRichard Henderson         struct rlimit lim;
673703e0e89SRichard Henderson         if (getrlimit(RLIMIT_STACK, &lim) == 0
67481bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur != RLIM_INFINITY
6750a3346b5SHelge Deller             && lim.rlim_cur == (target_long)lim.rlim_cur
6760a3346b5SHelge Deller             && lim.rlim_cur > guest_stack_size) {
677703e0e89SRichard Henderson             guest_stack_size = lim.rlim_cur;
678703e0e89SRichard Henderson         }
679703e0e89SRichard Henderson     }
680703e0e89SRichard Henderson 
681b1f9be31Sj_mayer     cpu_model = NULL;
682b5ec5ce0Sjohn cooper 
6836533dd6eSLluís Vilanova     qemu_add_opts(&qemu_trace_opts);
684f308f64eSLluís Vilanova     qemu_plugin_add_opts();
6856533dd6eSLluís Vilanova 
686fc9c5412SJohannes Schauer     optind = parse_args(argc, argv);
6874b5dfd82SPeter Maydell 
688b410253fSRichard Henderson     qemu_set_log_filename_flags(last_log_filename,
689b410253fSRichard Henderson                                 last_log_mask | (enable_strace * LOG_STRACE),
690b410253fSRichard Henderson                                 &error_fatal);
6914b25a506SJosh Kunz 
6926533dd6eSLluís Vilanova     if (!trace_init_backends()) {
6936533dd6eSLluís Vilanova         exit(1);
6946533dd6eSLluís Vilanova     }
69592eecfffSPaolo Bonzini     trace_init_file();
6960572f558SPaolo Bonzini     qemu_plugin_load_list(&plugins, &error_fatal);
6976533dd6eSLluís Vilanova 
69831e31b8aSbellard     /* Zero out regs */
69901ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
70031e31b8aSbellard 
70131e31b8aSbellard     /* Zero out image_info */
70231e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
70331e31b8aSbellard 
704edf8e2afSMika Westerberg     memset(&bprm, 0, sizeof (bprm));
705edf8e2afSMika Westerberg 
70674cd30b8Sbellard     /* Scan interp_prefix dir for replacement files. */
70774cd30b8Sbellard     init_paths(interp_prefix);
70874cd30b8Sbellard 
7094a24a758SPeter Maydell     init_qemu_uname_release();
7104a24a758SPeter Maydell 
7116e1c0d7bSLaurent Vivier     /*
7126e1c0d7bSLaurent Vivier      * Manage binfmt-misc open-binary flag
7136e1c0d7bSLaurent Vivier      */
714768fe76eSYunQiang Su     execfd = qemu_getauxval(AT_EXECFD);
715768fe76eSYunQiang Su     if (execfd == 0) {
7169d3019bcSLaurent Vivier         execfd = open(exec_path, O_RDONLY);
717768fe76eSYunQiang Su         if (execfd < 0) {
7189d3019bcSLaurent Vivier             printf("Error while loading %s: %s\n", exec_path, strerror(errno));
719768fe76eSYunQiang Su             _exit(EXIT_FAILURE);
720768fe76eSYunQiang Su         }
721768fe76eSYunQiang Su     }
722768fe76eSYunQiang Su 
7236e1c0d7bSLaurent Vivier     /*
7246e1c0d7bSLaurent Vivier      * get binfmt_misc flags
7256e1c0d7bSLaurent Vivier      */
7266e1c0d7bSLaurent Vivier     preserve_argv0 = !!(qemu_getauxval(AT_FLAGS) & AT_FLAGS_PRESERVE_ARGV0);
7276e1c0d7bSLaurent Vivier 
7286e1c0d7bSLaurent Vivier     /*
7296e1c0d7bSLaurent Vivier      * Manage binfmt-misc preserve-arg[0] flag
7306e1c0d7bSLaurent Vivier      *    argv[optind]     full path to the binary
7316e1c0d7bSLaurent Vivier      *    argv[optind + 1] original argv[0]
7326e1c0d7bSLaurent Vivier      */
7336e1c0d7bSLaurent Vivier     if (optind + 1 < argc && preserve_argv0) {
7346e1c0d7bSLaurent Vivier         optind++;
7356e1c0d7bSLaurent Vivier     }
7366e1c0d7bSLaurent Vivier 
73746027c07Sbellard     if (cpu_model == NULL) {
738768fe76eSYunQiang Su         cpu_model = cpu_get_model(get_elf_eflags(execfd));
739aaed909aSbellard     }
740c1c8cfe5SEduardo Habkost     cpu_type = parse_cpu_option(cpu_model);
7412278b939SIgor Mammedov 
7422b5249b8SIgor Mammedov     /* init tcg before creating CPUs and to get qemu_host_page_size */
743940e43aaSClaudio Fontana     {
744940e43aaSClaudio Fontana         AccelClass *ac = ACCEL_GET_CLASS(current_accel());
7452278b939SIgor Mammedov 
746b86f59c7SClaudio Fontana         accel_init_interfaces(ac);
74792242f34SClaudio Fontana         ac->init_machine(NULL);
748940e43aaSClaudio Fontana     }
7492278b939SIgor Mammedov     cpu = cpu_create(cpu_type);
7502994fd96SEduardo Habkost     env = cpu->env_ptr;
7510ac46af3SAndreas Färber     cpu_reset(cpu);
752db6b81d4SAndreas Färber     thread_cpu = cpu;
75354936004Sbellard 
7548f67b9c6SRichard Henderson     /*
7558f67b9c6SRichard Henderson      * Reserving too much vm space via mmap can run into problems
7568f67b9c6SRichard Henderson      * with rlimits, oom due to page table creation, etc.  We will
7578f67b9c6SRichard Henderson      * still try it, if directed by the command-line option, but
7588f67b9c6SRichard Henderson      * not by default.
7598f67b9c6SRichard Henderson      */
7608f67b9c6SRichard Henderson     max_reserved_va = MAX_RESERVED_VA(cpu);
7618f67b9c6SRichard Henderson     if (reserved_va != 0) {
7628f67b9c6SRichard Henderson         if (max_reserved_va && reserved_va > max_reserved_va) {
7638f67b9c6SRichard Henderson             fprintf(stderr, "Reserved virtual address too big\n");
7648f67b9c6SRichard Henderson             exit(EXIT_FAILURE);
7658f67b9c6SRichard Henderson         }
7668f67b9c6SRichard Henderson     } else if (HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32) {
7678f67b9c6SRichard Henderson         /*
7688f67b9c6SRichard Henderson          * reserved_va must be aligned with the host page size
7698f67b9c6SRichard Henderson          * as it is used with mmap()
7708f67b9c6SRichard Henderson          */
7718f67b9c6SRichard Henderson         reserved_va = max_reserved_va & qemu_host_page_mask;
7728f67b9c6SRichard Henderson     }
7738f67b9c6SRichard Henderson 
774a573e9baSRichard Henderson     {
775a573e9baSRichard Henderson         Error *err = NULL;
7765ebdd774SRichard Henderson         if (seed_optarg != NULL) {
777a573e9baSRichard Henderson             qemu_guest_random_seed_main(seed_optarg, &err);
778a573e9baSRichard Henderson         } else {
779a573e9baSRichard Henderson             qcrypto_init(&err);
780a573e9baSRichard Henderson         }
781a573e9baSRichard Henderson         if (err) {
782a573e9baSRichard Henderson             error_reportf_err(err, "cannot initialize crypto: ");
783a573e9baSRichard Henderson             exit(1);
784a573e9baSRichard Henderson         }
785c5e4a5a9SMagnus Reftel     }
786c5e4a5a9SMagnus Reftel 
78704a6dfebSaurel32     target_environ = envlist_to_environ(envlist, NULL);
78804a6dfebSaurel32     envlist_free(envlist);
789b12b6a18Sths 
790379f6698SPaul Brook     /*
791379f6698SPaul Brook      * Read in mmap_min_addr kernel parameter.  This value is used
792379f6698SPaul Brook      * When loading the ELF image to determine whether guest_base
79314f24e14SRichard Henderson      * is needed.  It is also used in mmap_find_vma.
794379f6698SPaul Brook      */
79514f24e14SRichard Henderson     {
796379f6698SPaul Brook         FILE *fp;
797379f6698SPaul Brook 
798379f6698SPaul Brook         if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
799379f6698SPaul Brook             unsigned long tmp;
800c9f80666SRichard Henderson             if (fscanf(fp, "%lu", &tmp) == 1 && tmp != 0) {
801379f6698SPaul Brook                 mmap_min_addr = tmp;
802c9f80666SRichard Henderson                 qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n",
803c9f80666SRichard Henderson                               mmap_min_addr);
804379f6698SPaul Brook             }
805379f6698SPaul Brook             fclose(fp);
806379f6698SPaul Brook         }
807379f6698SPaul Brook     }
808379f6698SPaul Brook 
8097d8cec95Saurel32     /*
810c9f80666SRichard Henderson      * We prefer to not make NULL pointers accessible to QEMU.
811c9f80666SRichard Henderson      * If we're in a chroot with no /proc, fall back to 1 page.
812c9f80666SRichard Henderson      */
813c9f80666SRichard Henderson     if (mmap_min_addr == 0) {
814c9f80666SRichard Henderson         mmap_min_addr = qemu_host_page_size;
815c9f80666SRichard Henderson         qemu_log_mask(CPU_LOG_PAGE,
816c9f80666SRichard Henderson                       "host mmap_min_addr=0x%lx (fallback)\n",
817c9f80666SRichard Henderson                       mmap_min_addr);
818c9f80666SRichard Henderson     }
819c9f80666SRichard Henderson 
820c9f80666SRichard Henderson     /*
8217d8cec95Saurel32      * Prepare copy of argv vector for target.
8227d8cec95Saurel32      */
8237d8cec95Saurel32     target_argc = argc - optind;
8247d8cec95Saurel32     target_argv = calloc(target_argc + 1, sizeof (char *));
8257d8cec95Saurel32     if (target_argv == NULL) {
8267d8cec95Saurel32         (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
8274d1275c2SRiku Voipio         exit(EXIT_FAILURE);
8287d8cec95Saurel32     }
8297d8cec95Saurel32 
8307d8cec95Saurel32     /*
8317d8cec95Saurel32      * If argv0 is specified (using '-0' switch) we replace
8327d8cec95Saurel32      * argv[0] pointer with the given one.
8337d8cec95Saurel32      */
8347d8cec95Saurel32     i = 0;
8357d8cec95Saurel32     if (argv0 != NULL) {
8367d8cec95Saurel32         target_argv[i++] = strdup(argv0);
8377d8cec95Saurel32     }
8387d8cec95Saurel32     for (; i < target_argc; i++) {
8397d8cec95Saurel32         target_argv[i] = strdup(argv[optind + i]);
8407d8cec95Saurel32     }
8417d8cec95Saurel32     target_argv[target_argc] = NULL;
8427d8cec95Saurel32 
843c78d65e8SMarkus Armbruster     ts = g_new0(TaskState, 1);
844edf8e2afSMika Westerberg     init_task_state(ts);
845edf8e2afSMika Westerberg     /* build Task State */
846edf8e2afSMika Westerberg     ts->info = info;
847edf8e2afSMika Westerberg     ts->bprm = &bprm;
8480429a971SAndreas Färber     cpu->opaque = ts;
849edf8e2afSMika Westerberg     task_settid(ts);
850edf8e2afSMika Westerberg 
851c093364fSOwen Anderson     fd_trans_init();
852c093364fSOwen Anderson 
8539d3019bcSLaurent Vivier     ret = loader_exec(execfd, exec_path, target_argv, target_environ, regs,
854fd4d81ddSArnaud Patard         info, &bprm);
855fd4d81ddSArnaud Patard     if (ret != 0) {
8569d3019bcSLaurent Vivier         printf("Error while loading %s: %s\n", exec_path, strerror(-ret));
8574d1275c2SRiku Voipio         _exit(EXIT_FAILURE);
85831e31b8aSbellard     }
85931e31b8aSbellard 
860b12b6a18Sths     for (wrk = target_environ; *wrk; wrk++) {
861ec45bbe5SSaurav Sachidanand         g_free(*wrk);
862b12b6a18Sths     }
863b12b6a18Sths 
864ec45bbe5SSaurav Sachidanand     g_free(target_environ);
865b12b6a18Sths 
86613829020SPaolo Bonzini     if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
86793756fdcSRichard Henderson         FILE *f = qemu_log_trylock();
86893756fdcSRichard Henderson         if (f) {
86993756fdcSRichard Henderson             fprintf(f, "guest_base  %p\n", (void *)guest_base);
87093756fdcSRichard Henderson             fprintf(f, "page layout changed following binary load\n");
87193756fdcSRichard Henderson             page_dump(f);
87254936004Sbellard 
87393756fdcSRichard Henderson             fprintf(f, "start_brk   0x" TARGET_ABI_FMT_lx "\n",
87493756fdcSRichard Henderson                     info->start_brk);
87593756fdcSRichard Henderson             fprintf(f, "end_code    0x" TARGET_ABI_FMT_lx "\n",
87693756fdcSRichard Henderson                     info->end_code);
87793756fdcSRichard Henderson             fprintf(f, "start_code  0x" TARGET_ABI_FMT_lx "\n",
87893756fdcSRichard Henderson                     info->start_code);
87993756fdcSRichard Henderson             fprintf(f, "start_data  0x" TARGET_ABI_FMT_lx "\n",
88093756fdcSRichard Henderson                     info->start_data);
88193756fdcSRichard Henderson             fprintf(f, "end_data    0x" TARGET_ABI_FMT_lx "\n",
88293756fdcSRichard Henderson                     info->end_data);
88393756fdcSRichard Henderson             fprintf(f, "start_stack 0x" TARGET_ABI_FMT_lx "\n",
88493756fdcSRichard Henderson                     info->start_stack);
88593756fdcSRichard Henderson             fprintf(f, "brk         0x" TARGET_ABI_FMT_lx "\n",
88693756fdcSRichard Henderson                     info->brk);
88793756fdcSRichard Henderson             fprintf(f, "entry       0x" TARGET_ABI_FMT_lx "\n",
88893756fdcSRichard Henderson                     info->entry);
88993756fdcSRichard Henderson             fprintf(f, "argv_start  0x" TARGET_ABI_FMT_lx "\n",
89060f1c801SRichard Henderson                     info->argv);
89193756fdcSRichard Henderson             fprintf(f, "env_start   0x" TARGET_ABI_FMT_lx "\n",
89260f1c801SRichard Henderson                     info->envp);
89393756fdcSRichard Henderson             fprintf(f, "auxv_start  0x" TARGET_ABI_FMT_lx "\n",
89493756fdcSRichard Henderson                     info->saved_auxv);
89593756fdcSRichard Henderson             qemu_log_unlock(f);
89693756fdcSRichard Henderson         }
8972e77eac6Sblueswir1     }
89831e31b8aSbellard 
89953a5960aSpbrook     target_set_brk(info->brk);
90031e31b8aSbellard     syscall_init();
90166fb9763Sbellard     signal_init();
90231e31b8aSbellard 
9039002ec79SRichard Henderson     /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
9049002ec79SRichard Henderson        generating the prologue until now so that the prologue can take
9059002ec79SRichard Henderson        the real value of GUEST_BASE into account.  */
906b1311c4aSEmilio G. Cota     tcg_prologue_init(tcg_ctx);
9079002ec79SRichard Henderson 
908cd71c089SLaurent Vivier     target_cpu_copy_regs(env, regs);
909cd71c089SLaurent Vivier 
910fcedd920SAlex Bennée     if (gdbstub) {
911fcedd920SAlex Bennée         if (gdbserver_start(gdbstub) < 0) {
912fcedd920SAlex Bennée             fprintf(stderr, "qemu: could not open gdbserver on %s\n",
913fcedd920SAlex Bennée                     gdbstub);
9144d1275c2SRiku Voipio             exit(EXIT_FAILURE);
915ff7a981aSPeter Maydell         }
916db6b81d4SAndreas Färber         gdb_handlesig(cpu, 0);
9171fddef4bSbellard     }
918e4a4aaa5SRichard Henderson 
919e4a4aaa5SRichard Henderson #ifdef CONFIG_SEMIHOSTING
920e4a4aaa5SRichard Henderson     qemu_semihosting_guestfd_init();
921e4a4aaa5SRichard Henderson #endif
922e4a4aaa5SRichard Henderson 
9231b6b029eSbellard     cpu_loop(env);
9241b6b029eSbellard     /* never exits */
92531e31b8aSbellard     return 0;
92631e31b8aSbellard }
927