xref: /qemu/linux-user/elfload.c (revision 49840a4a098149067789255bca6894645f411036)
131e31b8aSbellard /* This is the Linux kernel elf-loading code, ported into user space */
2d39594e9SPeter Maydell #include "qemu/osdep.h"
3edf8e2afSMika Westerberg #include <sys/param.h>
431e31b8aSbellard 
5edf8e2afSMika Westerberg #include <sys/resource.h>
630ab9ef2SRichard Henderson #include <sys/shm.h>
731e31b8aSbellard 
83ef693a0Sbellard #include "qemu.h"
93b249d26SPeter Maydell #include "user-internals.h"
10db2af69dSRichard Henderson #include "signal-common.h"
113ad0a769SPeter Maydell #include "loader.h"
125423e6d3SPeter Maydell #include "user-mmap.h"
1376cad711SPaolo Bonzini #include "disas/disas.h"
14ce543844SPhilippe Mathieu-Daudé #include "qemu/bitops.h"
15f348b6d1SVeronia Bahaa #include "qemu/path.h"
16dc5e9ac7SMarkus Armbruster #include "qemu/queue.h"
17c6a2377fSRichard Henderson #include "qemu/guest-random.h"
186fd59449SRichard Henderson #include "qemu/units.h"
19ee947430SAlex Bennée #include "qemu/selfmap.h"
20c7f17e7bSRichard Henderson #include "qapi/error.h"
21cc37d98bSRichard Henderson #include "qemu/error-report.h"
22db2af69dSRichard Henderson #include "target_signal.h"
237c10cb38SIlya Leoshkevich #include "accel/tcg/debuginfo.h"
2431e31b8aSbellard 
25e58ffeb3Smalc #ifdef _ARCH_PPC64
26a6cc84f4Smalc #undef ARCH_DLINFO
27a6cc84f4Smalc #undef ELF_PLATFORM
28a6cc84f4Smalc #undef ELF_HWCAP
29ad6919dcSPeter Maydell #undef ELF_HWCAP2
30a6cc84f4Smalc #undef ELF_CLASS
31a6cc84f4Smalc #undef ELF_DATA
32a6cc84f4Smalc #undef ELF_ARCH
33a6cc84f4Smalc #endif
34a6cc84f4Smalc 
35edf8e2afSMika Westerberg #define ELF_OSABI   ELFOSABI_SYSV
36edf8e2afSMika Westerberg 
37cb33da57Sblueswir1 /* from personality.h */
38cb33da57Sblueswir1 
39cb33da57Sblueswir1 /*
40cb33da57Sblueswir1  * Flags for bug emulation.
41cb33da57Sblueswir1  *
42cb33da57Sblueswir1  * These occupy the top three bytes.
43cb33da57Sblueswir1  */
44cb33da57Sblueswir1 enum {
45cb33da57Sblueswir1     ADDR_NO_RANDOMIZE = 0x0040000,      /* disable randomization of VA space */
46d97ef72eSRichard Henderson     FDPIC_FUNCPTRS =    0x0080000,      /* userspace function ptrs point to
47d97ef72eSRichard Henderson                                            descriptors (signal handling) */
48cb33da57Sblueswir1     MMAP_PAGE_ZERO =    0x0100000,
49cb33da57Sblueswir1     ADDR_COMPAT_LAYOUT = 0x0200000,
50cb33da57Sblueswir1     READ_IMPLIES_EXEC = 0x0400000,
51cb33da57Sblueswir1     ADDR_LIMIT_32BIT =  0x0800000,
52cb33da57Sblueswir1     SHORT_INODE =       0x1000000,
53cb33da57Sblueswir1     WHOLE_SECONDS =     0x2000000,
54cb33da57Sblueswir1     STICKY_TIMEOUTS =   0x4000000,
55cb33da57Sblueswir1     ADDR_LIMIT_3GB =    0x8000000,
56cb33da57Sblueswir1 };
57cb33da57Sblueswir1 
58cb33da57Sblueswir1 /*
59cb33da57Sblueswir1  * Personality types.
60cb33da57Sblueswir1  *
61cb33da57Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
62cb33da57Sblueswir1  * conflict with error returns.
63cb33da57Sblueswir1  */
64cb33da57Sblueswir1 enum {
65cb33da57Sblueswir1     PER_LINUX =         0x0000,
66cb33da57Sblueswir1     PER_LINUX_32BIT =   0x0000 | ADDR_LIMIT_32BIT,
67cb33da57Sblueswir1     PER_LINUX_FDPIC =   0x0000 | FDPIC_FUNCPTRS,
68cb33da57Sblueswir1     PER_SVR4 =          0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
69cb33da57Sblueswir1     PER_SVR3 =          0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
70d97ef72eSRichard Henderson     PER_SCOSVR3 =       0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE,
71cb33da57Sblueswir1     PER_OSR5 =          0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
72cb33da57Sblueswir1     PER_WYSEV386 =      0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
73cb33da57Sblueswir1     PER_ISCR4 =         0x0005 | STICKY_TIMEOUTS,
74cb33da57Sblueswir1     PER_BSD =           0x0006,
75cb33da57Sblueswir1     PER_SUNOS =         0x0006 | STICKY_TIMEOUTS,
76cb33da57Sblueswir1     PER_XENIX =         0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
77cb33da57Sblueswir1     PER_LINUX32 =       0x0008,
78cb33da57Sblueswir1     PER_LINUX32_3GB =   0x0008 | ADDR_LIMIT_3GB,
79cb33da57Sblueswir1     PER_IRIX32 =        0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
80cb33da57Sblueswir1     PER_IRIXN32 =       0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
81cb33da57Sblueswir1     PER_IRIX64 =        0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
82cb33da57Sblueswir1     PER_RISCOS =        0x000c,
83cb33da57Sblueswir1     PER_SOLARIS =       0x000d | STICKY_TIMEOUTS,
84cb33da57Sblueswir1     PER_UW7 =           0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
85cb33da57Sblueswir1     PER_OSF4 =          0x000f,                  /* OSF/1 v4 */
86cb33da57Sblueswir1     PER_HPUX =          0x0010,
87cb33da57Sblueswir1     PER_MASK =          0x00ff,
88cb33da57Sblueswir1 };
89cb33da57Sblueswir1 
90cb33da57Sblueswir1 /*
91cb33da57Sblueswir1  * Return the base personality without flags.
92cb33da57Sblueswir1  */
93cb33da57Sblueswir1 #define personality(pers)       (pers & PER_MASK)
94cb33da57Sblueswir1 
953cb10cfaSChristophe Lyon int info_is_fdpic(struct image_info *info)
963cb10cfaSChristophe Lyon {
973cb10cfaSChristophe Lyon     return info->personality == PER_LINUX_FDPIC;
983cb10cfaSChristophe Lyon }
993cb10cfaSChristophe Lyon 
10083fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
10183fb7adfSbellard #ifndef MAP_DENYWRITE
10283fb7adfSbellard #define MAP_DENYWRITE 0
10383fb7adfSbellard #endif
10483fb7adfSbellard 
10583fb7adfSbellard /* should probably go in elf.h */
10683fb7adfSbellard #ifndef ELIBBAD
10783fb7adfSbellard #define ELIBBAD 80
10883fb7adfSbellard #endif
10983fb7adfSbellard 
110ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
11128490231SRichard Henderson #define ELF_DATA        ELFDATA2MSB
11228490231SRichard Henderson #else
11328490231SRichard Henderson #define ELF_DATA        ELFDATA2LSB
11428490231SRichard Henderson #endif
11528490231SRichard Henderson 
116a29f998dSPaolo Bonzini #ifdef TARGET_ABI_MIPSN32
117918fc54cSPaolo Bonzini typedef abi_ullong      target_elf_greg_t;
118918fc54cSPaolo Bonzini #define tswapreg(ptr)   tswap64(ptr)
119a29f998dSPaolo Bonzini #else
120a29f998dSPaolo Bonzini typedef abi_ulong       target_elf_greg_t;
121a29f998dSPaolo Bonzini #define tswapreg(ptr)   tswapal(ptr)
122a29f998dSPaolo Bonzini #endif
123a29f998dSPaolo Bonzini 
12421e807faSNathan Froyd #ifdef USE_UID16
1251ddd592fSPaolo Bonzini typedef abi_ushort      target_uid_t;
1261ddd592fSPaolo Bonzini typedef abi_ushort      target_gid_t;
12721e807faSNathan Froyd #else
128f8fd4fc4SPaolo Bonzini typedef abi_uint        target_uid_t;
129f8fd4fc4SPaolo Bonzini typedef abi_uint        target_gid_t;
13021e807faSNathan Froyd #endif
131f8fd4fc4SPaolo Bonzini typedef abi_int         target_pid_t;
13221e807faSNathan Froyd 
13330ac07d4Sbellard #ifdef TARGET_I386
13430ac07d4Sbellard 
13515338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
13615338fd7Sbellard 
13715338fd7Sbellard static uint32_t get_elf_hwcap(void)
13815338fd7Sbellard {
139a2247f8eSAndreas Färber     X86CPU *cpu = X86_CPU(thread_cpu);
140a2247f8eSAndreas Färber 
141a2247f8eSAndreas Färber     return cpu->env.features[FEAT_1_EDX];
14215338fd7Sbellard }
14315338fd7Sbellard 
14484409ddbSj_mayer #ifdef TARGET_X86_64
14584409ddbSj_mayer #define ELF_START_MMAP 0x2aaaaab000ULL
14684409ddbSj_mayer 
14784409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
14884409ddbSj_mayer #define ELF_ARCH       EM_X86_64
14984409ddbSj_mayer 
1509263ba84SRichard Henderson #define ELF_PLATFORM   "x86_64"
1519263ba84SRichard Henderson 
15284409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
15384409ddbSj_mayer {
15484409ddbSj_mayer     regs->rax = 0;
15584409ddbSj_mayer     regs->rsp = infop->start_stack;
15684409ddbSj_mayer     regs->rip = infop->entry;
15784409ddbSj_mayer }
15884409ddbSj_mayer 
1599edc5d79SMika Westerberg #define ELF_NREG    27
160c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
1619edc5d79SMika Westerberg 
1629edc5d79SMika Westerberg /*
1639edc5d79SMika Westerberg  * Note that ELF_NREG should be 29 as there should be place for
1649edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
1659edc5d79SMika Westerberg  * those.
1669edc5d79SMika Westerberg  *
1679edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
1689edc5d79SMika Westerberg  */
16905390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
1709edc5d79SMika Westerberg {
171030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[15]);
172030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[14]);
173030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[13]);
174030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[12]);
175030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EBP]);
176030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBX]);
177030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[11]);
178030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->regs[10]);
179030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->regs[9]);
180030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->regs[8]);
181030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->regs[R_EAX]);
182030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_ECX]);
183030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->regs[R_EDX]);
184030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->regs[R_ESI]);
185030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->regs[R_EDI]);
186030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_EAX]); /* XXX */
187030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->eip);
188030912e0SIlya Leoshkevich     (*regs)[17] = tswapreg(env->segs[R_CS].selector & 0xffff);
189030912e0SIlya Leoshkevich     (*regs)[18] = tswapreg(env->eflags);
190030912e0SIlya Leoshkevich     (*regs)[19] = tswapreg(env->regs[R_ESP]);
191030912e0SIlya Leoshkevich     (*regs)[20] = tswapreg(env->segs[R_SS].selector & 0xffff);
192030912e0SIlya Leoshkevich     (*regs)[21] = tswapreg(env->segs[R_FS].selector & 0xffff);
193030912e0SIlya Leoshkevich     (*regs)[22] = tswapreg(env->segs[R_GS].selector & 0xffff);
194030912e0SIlya Leoshkevich     (*regs)[23] = tswapreg(env->segs[R_DS].selector & 0xffff);
195030912e0SIlya Leoshkevich     (*regs)[24] = tswapreg(env->segs[R_ES].selector & 0xffff);
196030912e0SIlya Leoshkevich     (*regs)[25] = tswapreg(env->segs[R_FS].selector & 0xffff);
197030912e0SIlya Leoshkevich     (*regs)[26] = tswapreg(env->segs[R_GS].selector & 0xffff);
1989edc5d79SMika Westerberg }
1999edc5d79SMika Westerberg 
200d461b73eSRichard Henderson #if ULONG_MAX > UINT32_MAX
201d461b73eSRichard Henderson #define INIT_GUEST_COMMPAGE
202d461b73eSRichard Henderson static bool init_guest_commpage(void)
203d461b73eSRichard Henderson {
204d461b73eSRichard Henderson     /*
205d461b73eSRichard Henderson      * The vsyscall page is at a high negative address aka kernel space,
206d461b73eSRichard Henderson      * which means that we cannot actually allocate it with target_mmap.
207d461b73eSRichard Henderson      * We still should be able to use page_set_flags, unless the user
208d461b73eSRichard Henderson      * has specified -R reserved_va, which would trigger an assert().
209d461b73eSRichard Henderson      */
210d461b73eSRichard Henderson     if (reserved_va != 0 &&
211d461b73eSRichard Henderson         TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE >= reserved_va) {
212d461b73eSRichard Henderson         error_report("Cannot allocate vsyscall page");
213d461b73eSRichard Henderson         exit(EXIT_FAILURE);
214d461b73eSRichard Henderson     }
215d461b73eSRichard Henderson     page_set_flags(TARGET_VSYSCALL_PAGE,
216*49840a4aSRichard Henderson                    TARGET_VSYSCALL_PAGE | ~TARGET_PAGE_MASK,
217d461b73eSRichard Henderson                    PAGE_EXEC | PAGE_VALID);
218d461b73eSRichard Henderson     return true;
219d461b73eSRichard Henderson }
220d461b73eSRichard Henderson #endif
22184409ddbSj_mayer #else
22284409ddbSj_mayer 
22330ac07d4Sbellard #define ELF_START_MMAP 0x80000000
22430ac07d4Sbellard 
22530ac07d4Sbellard /*
22630ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
22730ac07d4Sbellard  */
22830ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
22930ac07d4Sbellard 
23030ac07d4Sbellard /*
23130ac07d4Sbellard  * These are used to set parameters in the core dumps.
23230ac07d4Sbellard  */
23330ac07d4Sbellard #define ELF_CLASS       ELFCLASS32
23430ac07d4Sbellard #define ELF_ARCH        EM_386
23530ac07d4Sbellard 
2369263ba84SRichard Henderson #define ELF_PLATFORM get_elf_platform()
237872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
2389263ba84SRichard Henderson 
2399263ba84SRichard Henderson static const char *get_elf_platform(void)
2409263ba84SRichard Henderson {
2419263ba84SRichard Henderson     static char elf_platform[] = "i386";
2429263ba84SRichard Henderson     int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
2439263ba84SRichard Henderson     if (family > 6) {
2449263ba84SRichard Henderson         family = 6;
2459263ba84SRichard Henderson     }
2469263ba84SRichard Henderson     if (family >= 3) {
2479263ba84SRichard Henderson         elf_platform[1] = '0' + family;
2489263ba84SRichard Henderson     }
2499263ba84SRichard Henderson     return elf_platform;
2509263ba84SRichard Henderson }
2519263ba84SRichard Henderson 
252d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
253d97ef72eSRichard Henderson                                struct image_info *infop)
254e5fe0c52Spbrook {
255e5fe0c52Spbrook     regs->esp = infop->start_stack;
256e5fe0c52Spbrook     regs->eip = infop->entry;
257e5fe0c52Spbrook 
25830ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
25930ac07d4Sbellard        starts %edx contains a pointer to a function which might be
26030ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
26130ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
26230ac07d4Sbellard        that have been loaded before the code runs.
26330ac07d4Sbellard 
26430ac07d4Sbellard        A value of 0 tells we have no such handler.  */
265e5fe0c52Spbrook     regs->edx = 0;
266b346ff46Sbellard }
2679edc5d79SMika Westerberg 
2689edc5d79SMika Westerberg #define ELF_NREG    17
269c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
2709edc5d79SMika Westerberg 
2719edc5d79SMika Westerberg /*
2729edc5d79SMika Westerberg  * Note that ELF_NREG should be 19 as there should be place for
2739edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
2749edc5d79SMika Westerberg  * those.
2759edc5d79SMika Westerberg  *
2769edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
2779edc5d79SMika Westerberg  */
27805390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
2799edc5d79SMika Westerberg {
280030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[R_EBX]);
281030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[R_ECX]);
282030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[R_EDX]);
283030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[R_ESI]);
284030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EDI]);
285030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBP]);
286030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[R_EAX]);
287030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->segs[R_DS].selector & 0xffff);
288030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->segs[R_ES].selector & 0xffff);
289030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->segs[R_FS].selector & 0xffff);
290030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->segs[R_GS].selector & 0xffff);
291030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_EAX]); /* XXX */
292030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->eip);
293030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->segs[R_CS].selector & 0xffff);
294030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->eflags);
295030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_ESP]);
296030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->segs[R_SS].selector & 0xffff);
2979edc5d79SMika Westerberg }
29884409ddbSj_mayer #endif
299b346ff46Sbellard 
3009edc5d79SMika Westerberg #define USE_ELF_CORE_DUMP
301b346ff46Sbellard #define ELF_EXEC_PAGESIZE       4096
302b346ff46Sbellard 
303b346ff46Sbellard #endif
304b346ff46Sbellard 
305b346ff46Sbellard #ifdef TARGET_ARM
306b346ff46Sbellard 
30724e76ff0SPeter Maydell #ifndef TARGET_AARCH64
30824e76ff0SPeter Maydell /* 32 bit ARM definitions */
30924e76ff0SPeter Maydell 
310b346ff46Sbellard #define ELF_START_MMAP 0x80000000
311b346ff46Sbellard 
312b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_ARM
313b346ff46Sbellard #define ELF_CLASS       ELFCLASS32
314872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
315b346ff46Sbellard 
316d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
317d97ef72eSRichard Henderson                                struct image_info *infop)
318b346ff46Sbellard {
319992f48a0Sblueswir1     abi_long stack = infop->start_stack;
320b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
32199033caeSAlexander Graf 
322167e4cdcSPeter Maydell     regs->uregs[16] = ARM_CPU_MODE_USR;
323167e4cdcSPeter Maydell     if (infop->entry & 1) {
324167e4cdcSPeter Maydell         regs->uregs[16] |= CPSR_T;
325167e4cdcSPeter Maydell     }
326167e4cdcSPeter Maydell     regs->uregs[15] = infop->entry & 0xfffffffe;
327167e4cdcSPeter Maydell     regs->uregs[13] = infop->start_stack;
3282f619698Sbellard     /* FIXME - what to for failure of get_user()? */
329167e4cdcSPeter Maydell     get_user_ual(regs->uregs[2], stack + 8); /* envp */
330167e4cdcSPeter Maydell     get_user_ual(regs->uregs[1], stack + 4); /* envp */
331a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
332167e4cdcSPeter Maydell     regs->uregs[0] = 0;
333e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
334863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
335167e4cdcSPeter Maydell     regs->uregs[10] = infop->start_data;
3363cb10cfaSChristophe Lyon 
3373cb10cfaSChristophe Lyon     /* Support ARM FDPIC.  */
3383cb10cfaSChristophe Lyon     if (info_is_fdpic(infop)) {
3393cb10cfaSChristophe Lyon         /* As described in the ABI document, r7 points to the loadmap info
3403cb10cfaSChristophe Lyon          * prepared by the kernel. If an interpreter is needed, r8 points
3413cb10cfaSChristophe Lyon          * to the interpreter loadmap and r9 points to the interpreter
3423cb10cfaSChristophe Lyon          * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
3433cb10cfaSChristophe Lyon          * r9 points to the main program PT_DYNAMIC info.
3443cb10cfaSChristophe Lyon          */
3453cb10cfaSChristophe Lyon         regs->uregs[7] = infop->loadmap_addr;
3463cb10cfaSChristophe Lyon         if (infop->interpreter_loadmap_addr) {
3473cb10cfaSChristophe Lyon             /* Executable is dynamically loaded.  */
3483cb10cfaSChristophe Lyon             regs->uregs[8] = infop->interpreter_loadmap_addr;
3493cb10cfaSChristophe Lyon             regs->uregs[9] = infop->interpreter_pt_dynamic_addr;
3503cb10cfaSChristophe Lyon         } else {
3513cb10cfaSChristophe Lyon             regs->uregs[8] = 0;
3523cb10cfaSChristophe Lyon             regs->uregs[9] = infop->pt_dynamic_addr;
3533cb10cfaSChristophe Lyon         }
3543cb10cfaSChristophe Lyon     }
355b346ff46Sbellard }
356b346ff46Sbellard 
357edf8e2afSMika Westerberg #define ELF_NREG    18
358c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
359edf8e2afSMika Westerberg 
36005390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUARMState *env)
361edf8e2afSMika Westerberg {
36286cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->regs[0]);
36386cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->regs[1]);
36486cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->regs[2]);
36586cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->regs[3]);
36686cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->regs[4]);
36786cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->regs[5]);
36886cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->regs[6]);
36986cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->regs[7]);
37086cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->regs[8]);
37186cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->regs[9]);
37286cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->regs[10]);
37386cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->regs[11]);
37486cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->regs[12]);
37586cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->regs[13]);
37686cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->regs[14]);
37786cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->regs[15]);
378edf8e2afSMika Westerberg 
37986cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(cpsr_read((CPUARMState *)env));
38086cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->regs[0]); /* XXX */
381edf8e2afSMika Westerberg }
382edf8e2afSMika Westerberg 
38330ac07d4Sbellard #define USE_ELF_CORE_DUMP
38430ac07d4Sbellard #define ELF_EXEC_PAGESIZE       4096
38530ac07d4Sbellard 
386afce2927Sbellard enum
387afce2927Sbellard {
388afce2927Sbellard     ARM_HWCAP_ARM_SWP       = 1 << 0,
389afce2927Sbellard     ARM_HWCAP_ARM_HALF      = 1 << 1,
390afce2927Sbellard     ARM_HWCAP_ARM_THUMB     = 1 << 2,
391afce2927Sbellard     ARM_HWCAP_ARM_26BIT     = 1 << 3,
392afce2927Sbellard     ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
393afce2927Sbellard     ARM_HWCAP_ARM_FPA       = 1 << 5,
394afce2927Sbellard     ARM_HWCAP_ARM_VFP       = 1 << 6,
395afce2927Sbellard     ARM_HWCAP_ARM_EDSP      = 1 << 7,
396cf6de34aSRiku Voipio     ARM_HWCAP_ARM_JAVA      = 1 << 8,
397cf6de34aSRiku Voipio     ARM_HWCAP_ARM_IWMMXT    = 1 << 9,
39843ce393eSPeter Maydell     ARM_HWCAP_ARM_CRUNCH    = 1 << 10,
39943ce393eSPeter Maydell     ARM_HWCAP_ARM_THUMBEE   = 1 << 11,
40043ce393eSPeter Maydell     ARM_HWCAP_ARM_NEON      = 1 << 12,
40143ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3     = 1 << 13,
40243ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3D16  = 1 << 14,
40324682654SPeter Maydell     ARM_HWCAP_ARM_TLS       = 1 << 15,
40424682654SPeter Maydell     ARM_HWCAP_ARM_VFPv4     = 1 << 16,
40524682654SPeter Maydell     ARM_HWCAP_ARM_IDIVA     = 1 << 17,
40624682654SPeter Maydell     ARM_HWCAP_ARM_IDIVT     = 1 << 18,
40724682654SPeter Maydell     ARM_HWCAP_ARM_VFPD32    = 1 << 19,
40824682654SPeter Maydell     ARM_HWCAP_ARM_LPAE      = 1 << 20,
40924682654SPeter Maydell     ARM_HWCAP_ARM_EVTSTRM   = 1 << 21,
410afce2927Sbellard };
411afce2927Sbellard 
412ad6919dcSPeter Maydell enum {
413ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_AES      = 1 << 0,
414ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_PMULL    = 1 << 1,
415ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA1     = 1 << 2,
416ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA2     = 1 << 3,
417ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_CRC32    = 1 << 4,
418ad6919dcSPeter Maydell };
419ad6919dcSPeter Maydell 
4206b1275ffSPeter Maydell /* The commpage only exists for 32 bit kernels */
4216b1275ffSPeter Maydell 
42266346fafSRichard Henderson #define HI_COMMPAGE (intptr_t)0xffff0f00u
423ee947430SAlex Bennée 
424ee947430SAlex Bennée static bool init_guest_commpage(void)
42597cc7560SDr. David Alan Gilbert {
426fbd3c4cfSRichard Henderson     abi_ptr commpage = HI_COMMPAGE & -qemu_host_page_size;
427fbd3c4cfSRichard Henderson     void *want = g2h_untagged(commpage);
428ee947430SAlex Bennée     void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
4295c3e87f3SAlex Bennée                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
43097cc7560SDr. David Alan Gilbert 
431ee947430SAlex Bennée     if (addr == MAP_FAILED) {
432ee947430SAlex Bennée         perror("Allocating guest commpage");
433ee947430SAlex Bennée         exit(EXIT_FAILURE);
434ee947430SAlex Bennée     }
435ee947430SAlex Bennée     if (addr != want) {
436ee947430SAlex Bennée         return false;
437806d1021SMeador Inge     }
438806d1021SMeador Inge 
439ee947430SAlex Bennée     /* Set kernel helper versions; rest of page is 0.  */
4403e8f1628SRichard Henderson     __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu));
44197cc7560SDr. David Alan Gilbert 
442ee947430SAlex Bennée     if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
44397cc7560SDr. David Alan Gilbert         perror("Protecting guest commpage");
444ee947430SAlex Bennée         exit(EXIT_FAILURE);
44597cc7560SDr. David Alan Gilbert     }
446fbd3c4cfSRichard Henderson 
447*49840a4aSRichard Henderson     page_set_flags(commpage, commpage | ~qemu_host_page_mask,
448fbd3c4cfSRichard Henderson                    PAGE_READ | PAGE_EXEC | PAGE_VALID);
449ee947430SAlex Bennée     return true;
45097cc7560SDr. David Alan Gilbert }
451adf050b1SBenoit Canet 
452adf050b1SBenoit Canet #define ELF_HWCAP get_elf_hwcap()
453ad6919dcSPeter Maydell #define ELF_HWCAP2 get_elf_hwcap2()
454adf050b1SBenoit Canet 
455adf050b1SBenoit Canet static uint32_t get_elf_hwcap(void)
456adf050b1SBenoit Canet {
457a2247f8eSAndreas Färber     ARMCPU *cpu = ARM_CPU(thread_cpu);
458adf050b1SBenoit Canet     uint32_t hwcaps = 0;
459adf050b1SBenoit Canet 
460adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_SWP;
461adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_HALF;
462adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_THUMB;
463adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
464adf050b1SBenoit Canet 
465adf050b1SBenoit Canet     /* probe for the extra features */
466adf050b1SBenoit Canet #define GET_FEATURE(feat, hwcap) \
467a2247f8eSAndreas Färber     do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
468962fcbf2SRichard Henderson 
469962fcbf2SRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
470962fcbf2SRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
471962fcbf2SRichard Henderson 
47224682654SPeter Maydell     /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
47324682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
474adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
475adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
476adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
47724682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
478bfa8a370SRichard Henderson     GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
479873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
480873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
481bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP);
482bfa8a370SRichard Henderson 
483bfa8a370SRichard Henderson     if (cpu_isar_feature(aa32_fpsp_v3, cpu) ||
484bfa8a370SRichard Henderson         cpu_isar_feature(aa32_fpdp_v3, cpu)) {
485bfa8a370SRichard Henderson         hwcaps |= ARM_HWCAP_ARM_VFPv3;
486bfa8a370SRichard Henderson         if (cpu_isar_feature(aa32_simd_r32, cpu)) {
487bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPD32;
488bfa8a370SRichard Henderson         } else {
489bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPv3D16;
490bfa8a370SRichard Henderson         }
491bfa8a370SRichard Henderson     }
492bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4);
493adf050b1SBenoit Canet 
494adf050b1SBenoit Canet     return hwcaps;
495adf050b1SBenoit Canet }
496afce2927Sbellard 
497ad6919dcSPeter Maydell static uint32_t get_elf_hwcap2(void)
498ad6919dcSPeter Maydell {
499ad6919dcSPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
500ad6919dcSPeter Maydell     uint32_t hwcaps = 0;
501ad6919dcSPeter Maydell 
502962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_aes, ARM_HWCAP2_ARM_AES);
503962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_pmull, ARM_HWCAP2_ARM_PMULL);
504962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha1, ARM_HWCAP2_ARM_SHA1);
505962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha2, ARM_HWCAP2_ARM_SHA2);
506962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_crc32, ARM_HWCAP2_ARM_CRC32);
507ad6919dcSPeter Maydell     return hwcaps;
508ad6919dcSPeter Maydell }
509ad6919dcSPeter Maydell 
510ad6919dcSPeter Maydell #undef GET_FEATURE
511962fcbf2SRichard Henderson #undef GET_FEATURE_ID
512ad6919dcSPeter Maydell 
51313ec4ec3SRichard Henderson #define ELF_PLATFORM get_elf_platform()
51413ec4ec3SRichard Henderson 
51513ec4ec3SRichard Henderson static const char *get_elf_platform(void)
51613ec4ec3SRichard Henderson {
51713ec4ec3SRichard Henderson     CPUARMState *env = thread_cpu->env_ptr;
51813ec4ec3SRichard Henderson 
519ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
52013ec4ec3SRichard Henderson # define END  "b"
52113ec4ec3SRichard Henderson #else
52213ec4ec3SRichard Henderson # define END  "l"
52313ec4ec3SRichard Henderson #endif
52413ec4ec3SRichard Henderson 
52513ec4ec3SRichard Henderson     if (arm_feature(env, ARM_FEATURE_V8)) {
52613ec4ec3SRichard Henderson         return "v8" END;
52713ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V7)) {
52813ec4ec3SRichard Henderson         if (arm_feature(env, ARM_FEATURE_M)) {
52913ec4ec3SRichard Henderson             return "v7m" END;
53013ec4ec3SRichard Henderson         } else {
53113ec4ec3SRichard Henderson             return "v7" END;
53213ec4ec3SRichard Henderson         }
53313ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V6)) {
53413ec4ec3SRichard Henderson         return "v6" END;
53513ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V5)) {
53613ec4ec3SRichard Henderson         return "v5" END;
53713ec4ec3SRichard Henderson     } else {
53813ec4ec3SRichard Henderson         return "v4" END;
53913ec4ec3SRichard Henderson     }
54013ec4ec3SRichard Henderson 
54113ec4ec3SRichard Henderson #undef END
54213ec4ec3SRichard Henderson }
54313ec4ec3SRichard Henderson 
54424e76ff0SPeter Maydell #else
54524e76ff0SPeter Maydell /* 64 bit ARM definitions */
54624e76ff0SPeter Maydell #define ELF_START_MMAP 0x80000000
54724e76ff0SPeter Maydell 
548b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_AARCH64
54924e76ff0SPeter Maydell #define ELF_CLASS       ELFCLASS64
550ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
551e20e3ec9SRichard Henderson # define ELF_PLATFORM    "aarch64_be"
552e20e3ec9SRichard Henderson #else
55324e76ff0SPeter Maydell # define ELF_PLATFORM    "aarch64"
554e20e3ec9SRichard Henderson #endif
55524e76ff0SPeter Maydell 
55624e76ff0SPeter Maydell static inline void init_thread(struct target_pt_regs *regs,
55724e76ff0SPeter Maydell                                struct image_info *infop)
55824e76ff0SPeter Maydell {
55924e76ff0SPeter Maydell     abi_long stack = infop->start_stack;
56024e76ff0SPeter Maydell     memset(regs, 0, sizeof(*regs));
56124e76ff0SPeter Maydell 
56224e76ff0SPeter Maydell     regs->pc = infop->entry & ~0x3ULL;
56324e76ff0SPeter Maydell     regs->sp = stack;
56424e76ff0SPeter Maydell }
56524e76ff0SPeter Maydell 
56624e76ff0SPeter Maydell #define ELF_NREG    34
56724e76ff0SPeter Maydell typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
56824e76ff0SPeter Maydell 
56924e76ff0SPeter Maydell static void elf_core_copy_regs(target_elf_gregset_t *regs,
57024e76ff0SPeter Maydell                                const CPUARMState *env)
57124e76ff0SPeter Maydell {
57224e76ff0SPeter Maydell     int i;
57324e76ff0SPeter Maydell 
57424e76ff0SPeter Maydell     for (i = 0; i < 32; i++) {
57524e76ff0SPeter Maydell         (*regs)[i] = tswapreg(env->xregs[i]);
57624e76ff0SPeter Maydell     }
57724e76ff0SPeter Maydell     (*regs)[32] = tswapreg(env->pc);
57824e76ff0SPeter Maydell     (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env));
57924e76ff0SPeter Maydell }
58024e76ff0SPeter Maydell 
58124e76ff0SPeter Maydell #define USE_ELF_CORE_DUMP
58224e76ff0SPeter Maydell #define ELF_EXEC_PAGESIZE       4096
58324e76ff0SPeter Maydell 
58424e76ff0SPeter Maydell enum {
58524e76ff0SPeter Maydell     ARM_HWCAP_A64_FP            = 1 << 0,
58624e76ff0SPeter Maydell     ARM_HWCAP_A64_ASIMD         = 1 << 1,
58724e76ff0SPeter Maydell     ARM_HWCAP_A64_EVTSTRM       = 1 << 2,
58824e76ff0SPeter Maydell     ARM_HWCAP_A64_AES           = 1 << 3,
58924e76ff0SPeter Maydell     ARM_HWCAP_A64_PMULL         = 1 << 4,
59024e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA1          = 1 << 5,
59124e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA2          = 1 << 6,
59224e76ff0SPeter Maydell     ARM_HWCAP_A64_CRC32         = 1 << 7,
593955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ATOMICS       = 1 << 8,
594955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FPHP          = 1 << 9,
595955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDHP       = 1 << 10,
596955f56d4SArd Biesheuvel     ARM_HWCAP_A64_CPUID         = 1 << 11,
597955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDRDM      = 1 << 12,
598955f56d4SArd Biesheuvel     ARM_HWCAP_A64_JSCVT         = 1 << 13,
599955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FCMA          = 1 << 14,
600955f56d4SArd Biesheuvel     ARM_HWCAP_A64_LRCPC         = 1 << 15,
601955f56d4SArd Biesheuvel     ARM_HWCAP_A64_DCPOP         = 1 << 16,
602955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA3          = 1 << 17,
603955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM3           = 1 << 18,
604955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM4           = 1 << 19,
605955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDDP       = 1 << 20,
606955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA512        = 1 << 21,
607955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SVE           = 1 << 22,
6080083a1faSRichard Henderson     ARM_HWCAP_A64_ASIMDFHM      = 1 << 23,
6090083a1faSRichard Henderson     ARM_HWCAP_A64_DIT           = 1 << 24,
6100083a1faSRichard Henderson     ARM_HWCAP_A64_USCAT         = 1 << 25,
6110083a1faSRichard Henderson     ARM_HWCAP_A64_ILRCPC        = 1 << 26,
6120083a1faSRichard Henderson     ARM_HWCAP_A64_FLAGM         = 1 << 27,
6130083a1faSRichard Henderson     ARM_HWCAP_A64_SSBS          = 1 << 28,
6140083a1faSRichard Henderson     ARM_HWCAP_A64_SB            = 1 << 29,
6150083a1faSRichard Henderson     ARM_HWCAP_A64_PACA          = 1 << 30,
6160083a1faSRichard Henderson     ARM_HWCAP_A64_PACG          = 1UL << 31,
6172041df4aSRichard Henderson 
6182041df4aSRichard Henderson     ARM_HWCAP2_A64_DCPODP       = 1 << 0,
6192041df4aSRichard Henderson     ARM_HWCAP2_A64_SVE2         = 1 << 1,
6202041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEAES       = 1 << 2,
6212041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEPMULL     = 1 << 3,
6222041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEBITPERM   = 1 << 4,
6232041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESHA3      = 1 << 5,
6242041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESM4       = 1 << 6,
6252041df4aSRichard Henderson     ARM_HWCAP2_A64_FLAGM2       = 1 << 7,
6262041df4aSRichard Henderson     ARM_HWCAP2_A64_FRINT        = 1 << 8,
62768948d18SRichard Henderson     ARM_HWCAP2_A64_SVEI8MM      = 1 << 9,
62868948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF32MM     = 1 << 10,
62968948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF64MM     = 1 << 11,
63068948d18SRichard Henderson     ARM_HWCAP2_A64_SVEBF16      = 1 << 12,
63168948d18SRichard Henderson     ARM_HWCAP2_A64_I8MM         = 1 << 13,
63268948d18SRichard Henderson     ARM_HWCAP2_A64_BF16         = 1 << 14,
63368948d18SRichard Henderson     ARM_HWCAP2_A64_DGH          = 1 << 15,
63468948d18SRichard Henderson     ARM_HWCAP2_A64_RNG          = 1 << 16,
63568948d18SRichard Henderson     ARM_HWCAP2_A64_BTI          = 1 << 17,
63668948d18SRichard Henderson     ARM_HWCAP2_A64_MTE          = 1 << 18,
637f9982ceaSRichard Henderson     ARM_HWCAP2_A64_ECV          = 1 << 19,
638f9982ceaSRichard Henderson     ARM_HWCAP2_A64_AFP          = 1 << 20,
639f9982ceaSRichard Henderson     ARM_HWCAP2_A64_RPRES        = 1 << 21,
640f9982ceaSRichard Henderson     ARM_HWCAP2_A64_MTE3         = 1 << 22,
641f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME          = 1 << 23,
642f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I16I64   = 1 << 24,
643f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F64F64   = 1 << 25,
644f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I8I32    = 1 << 26,
645f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F16F32   = 1 << 27,
646f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_B16F32   = 1 << 28,
647f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F32F32   = 1 << 29,
648f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_FA64     = 1 << 30,
64924e76ff0SPeter Maydell };
65024e76ff0SPeter Maydell 
65124e76ff0SPeter Maydell #define ELF_HWCAP   get_elf_hwcap()
6522041df4aSRichard Henderson #define ELF_HWCAP2  get_elf_hwcap2()
6532041df4aSRichard Henderson 
6542041df4aSRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
6552041df4aSRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
65624e76ff0SPeter Maydell 
65724e76ff0SPeter Maydell static uint32_t get_elf_hwcap(void)
65824e76ff0SPeter Maydell {
65924e76ff0SPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
66024e76ff0SPeter Maydell     uint32_t hwcaps = 0;
66124e76ff0SPeter Maydell 
66224e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_FP;
66324e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_ASIMD;
66437020ff1SAlex Bennée     hwcaps |= ARM_HWCAP_A64_CPUID;
66524e76ff0SPeter Maydell 
66624e76ff0SPeter Maydell     /* probe for the extra features */
667962fcbf2SRichard Henderson 
668962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES);
669962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL);
670962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha1, ARM_HWCAP_A64_SHA1);
671962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha256, ARM_HWCAP_A64_SHA2);
672962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha512, ARM_HWCAP_A64_SHA512);
673962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_crc32, ARM_HWCAP_A64_CRC32);
674962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha3, ARM_HWCAP_A64_SHA3);
675962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm3, ARM_HWCAP_A64_SM3);
676962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm4, ARM_HWCAP_A64_SM4);
6775763190fSRichard Henderson     GET_FEATURE_ID(aa64_fp16, ARM_HWCAP_A64_FPHP | ARM_HWCAP_A64_ASIMDHP);
678962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_atomics, ARM_HWCAP_A64_ATOMICS);
679962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_rdm, ARM_HWCAP_A64_ASIMDRDM);
680962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_dp, ARM_HWCAP_A64_ASIMDDP);
681962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA);
682cd208a1cSRichard Henderson     GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE);
68329d26ab2SRichard Henderson     GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG);
6841c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM);
6851c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
6869888bd1eSRichard Henderson     GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
687b89d9c98SRichard Henderson     GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
6880d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
6892677cf9fSPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
690a1229109SPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
691962fcbf2SRichard Henderson 
6922041df4aSRichard Henderson     return hwcaps;
6932041df4aSRichard Henderson }
6942041df4aSRichard Henderson 
6952041df4aSRichard Henderson static uint32_t get_elf_hwcap2(void)
6962041df4aSRichard Henderson {
6972041df4aSRichard Henderson     ARMCPU *cpu = ARM_CPU(thread_cpu);
6982041df4aSRichard Henderson     uint32_t hwcaps = 0;
6992041df4aSRichard Henderson 
7000d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
701cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2, ARM_HWCAP2_A64_SVE2);
702cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_aes, ARM_HWCAP2_A64_SVEAES);
703cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_pmull128, ARM_HWCAP2_A64_SVEPMULL);
704cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_bitperm, ARM_HWCAP2_A64_SVEBITPERM);
705cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sha3, ARM_HWCAP2_A64_SVESHA3);
706cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sm4, ARM_HWCAP2_A64_SVESM4);
7072041df4aSRichard Henderson     GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
7082041df4aSRichard Henderson     GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
709cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_i8mm, ARM_HWCAP2_A64_SVEI8MM);
710cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f32mm, ARM_HWCAP2_A64_SVEF32MM);
711cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f64mm, ARM_HWCAP2_A64_SVEF64MM);
7126c47a905SRichard Henderson     GET_FEATURE_ID(aa64_sve_bf16, ARM_HWCAP2_A64_SVEBF16);
713cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_i8mm, ARM_HWCAP2_A64_I8MM);
7146c47a905SRichard Henderson     GET_FEATURE_ID(aa64_bf16, ARM_HWCAP2_A64_BF16);
71568948d18SRichard Henderson     GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG);
71668948d18SRichard Henderson     GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI);
71768948d18SRichard Henderson     GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE);
718f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme, (ARM_HWCAP2_A64_SME |
719f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F32F32 |
720f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_B16F32 |
721f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F16F32 |
722f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_I8I32));
723f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_f64f64, ARM_HWCAP2_A64_SME_F64F64);
724f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_i16i64, ARM_HWCAP2_A64_SME_I16I64);
725f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_fa64, ARM_HWCAP2_A64_SME_FA64);
72624e76ff0SPeter Maydell 
72724e76ff0SPeter Maydell     return hwcaps;
72824e76ff0SPeter Maydell }
72924e76ff0SPeter Maydell 
7302041df4aSRichard Henderson #undef GET_FEATURE_ID
7312041df4aSRichard Henderson 
73224e76ff0SPeter Maydell #endif /* not TARGET_AARCH64 */
73324e76ff0SPeter Maydell #endif /* TARGET_ARM */
73430ac07d4Sbellard 
735853d6f7aSbellard #ifdef TARGET_SPARC
736a315a145Sbellard #ifdef TARGET_SPARC64
737853d6f7aSbellard 
738853d6f7aSbellard #define ELF_START_MMAP 0x80000000
739cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
740cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV | HWCAP_SPARC_V9)
741992f48a0Sblueswir1 #ifndef TARGET_ABI32
742cb33da57Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
743992f48a0Sblueswir1 #else
744992f48a0Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
745992f48a0Sblueswir1 #endif
746853d6f7aSbellard 
747a315a145Sbellard #define ELF_CLASS   ELFCLASS64
7485ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
749a315a145Sbellard #else
750a315a145Sbellard #define ELF_START_MMAP 0x80000000
751cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
752cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV)
753853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
754853d6f7aSbellard #define ELF_ARCH    EM_SPARC
755089a2256SRichard Henderson #endif /* TARGET_SPARC64 */
756853d6f7aSbellard 
757d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
758d97ef72eSRichard Henderson                                struct image_info *infop)
759853d6f7aSbellard {
760089a2256SRichard Henderson     /* Note that target_cpu_copy_regs does not read psr/tstate. */
761f5155289Sbellard     regs->pc = infop->entry;
762f5155289Sbellard     regs->npc = regs->pc + 4;
763f5155289Sbellard     regs->y = 0;
764089a2256SRichard Henderson     regs->u_regs[14] = (infop->start_stack - 16 * sizeof(abi_ulong)
765089a2256SRichard Henderson                         - TARGET_STACK_BIAS);
766853d6f7aSbellard }
767089a2256SRichard Henderson #endif /* TARGET_SPARC */
768853d6f7aSbellard 
76967867308Sbellard #ifdef TARGET_PPC
77067867308Sbellard 
7714ecd4d16SPeter Crosthwaite #define ELF_MACHINE    PPC_ELF_MACHINE
77267867308Sbellard #define ELF_START_MMAP 0x80000000
77367867308Sbellard 
77474154d7eSThomas Huth #if defined(TARGET_PPC64)
77584409ddbSj_mayer 
77684409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
77784409ddbSj_mayer 
77884409ddbSj_mayer #define ELF_CLASS       ELFCLASS64
77984409ddbSj_mayer 
78084409ddbSj_mayer #else
78184409ddbSj_mayer 
78267867308Sbellard #define ELF_CLASS       ELFCLASS32
783872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
78484409ddbSj_mayer 
78584409ddbSj_mayer #endif
78684409ddbSj_mayer 
78767867308Sbellard #define ELF_ARCH        EM_PPC
78867867308Sbellard 
789df84e4f3SNathan Froyd /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
790df84e4f3SNathan Froyd    See arch/powerpc/include/asm/cputable.h.  */
791df84e4f3SNathan Froyd enum {
7923efa9a67Smalc     QEMU_PPC_FEATURE_32 = 0x80000000,
7933efa9a67Smalc     QEMU_PPC_FEATURE_64 = 0x40000000,
7943efa9a67Smalc     QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
7953efa9a67Smalc     QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
7963efa9a67Smalc     QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
7973efa9a67Smalc     QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
7983efa9a67Smalc     QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
7993efa9a67Smalc     QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
8003efa9a67Smalc     QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
8013efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
8023efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
8033efa9a67Smalc     QEMU_PPC_FEATURE_NO_TB = 0x00100000,
8043efa9a67Smalc     QEMU_PPC_FEATURE_POWER4 = 0x00080000,
8053efa9a67Smalc     QEMU_PPC_FEATURE_POWER5 = 0x00040000,
8063efa9a67Smalc     QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
8073efa9a67Smalc     QEMU_PPC_FEATURE_CELL = 0x00010000,
8083efa9a67Smalc     QEMU_PPC_FEATURE_BOOKE = 0x00008000,
8093efa9a67Smalc     QEMU_PPC_FEATURE_SMT = 0x00004000,
8103efa9a67Smalc     QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
8113efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
8123efa9a67Smalc     QEMU_PPC_FEATURE_PA6T = 0x00000800,
8133efa9a67Smalc     QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
8143efa9a67Smalc     QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
8153efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
8163efa9a67Smalc     QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
8173efa9a67Smalc     QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
818df84e4f3SNathan Froyd 
8193efa9a67Smalc     QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
8203efa9a67Smalc     QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
821a60438ddSTom Musta 
822a60438ddSTom Musta     /* Feature definitions in AT_HWCAP2.  */
823a60438ddSTom Musta     QEMU_PPC_FEATURE2_ARCH_2_07 = 0x80000000, /* ISA 2.07 */
824a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_HTM = 0x40000000, /* Hardware Transactional Memory */
825a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_DSCR = 0x20000000, /* Data Stream Control Register */
826a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */
827a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */
828a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */
82924c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_VEC_CRYPTO = 0x02000000,
83024c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NOSC = 0x01000000,
831be0c46d4SSandipan Das     QEMU_PPC_FEATURE2_ARCH_3_00 = 0x00800000, /* ISA 3.00 */
83224c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HAS_IEEE128 = 0x00400000, /* VSX IEEE Bin Float 128-bit */
83324c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */
83424c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */
83524c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */
83696c343ccSJoel Stanley     QEMU_PPC_FEATURE2_ARCH_3_1 = 0x00040000, /* ISA 3.1 */
83796c343ccSJoel Stanley     QEMU_PPC_FEATURE2_MMA = 0x00020000, /* Matrix-Multiply Assist */
838df84e4f3SNathan Froyd };
839df84e4f3SNathan Froyd 
840df84e4f3SNathan Froyd #define ELF_HWCAP get_elf_hwcap()
841df84e4f3SNathan Froyd 
842df84e4f3SNathan Froyd static uint32_t get_elf_hwcap(void)
843df84e4f3SNathan Froyd {
844a2247f8eSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
845df84e4f3SNathan Froyd     uint32_t features = 0;
846df84e4f3SNathan Froyd 
847df84e4f3SNathan Froyd     /* We don't have to be terribly complete here; the high points are
848df84e4f3SNathan Froyd        Altivec/FP/SPE support.  Anything else is just a bonus.  */
849df84e4f3SNathan Froyd #define GET_FEATURE(flag, feature)                                      \
850a2247f8eSAndreas Färber     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
85158eb5308SMichael Walle #define GET_FEATURE2(flags, feature) \
85258eb5308SMichael Walle     do { \
85358eb5308SMichael Walle         if ((cpu->env.insns_flags2 & flags) == flags) { \
85458eb5308SMichael Walle             features |= feature; \
85558eb5308SMichael Walle         } \
85658eb5308SMichael Walle     } while (0)
8573efa9a67Smalc     GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
8583efa9a67Smalc     GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
8593efa9a67Smalc     GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
8603efa9a67Smalc     GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
8613efa9a67Smalc     GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
8623efa9a67Smalc     GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
8633efa9a67Smalc     GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
8643efa9a67Smalc     GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
8650e019746STom Musta     GET_FEATURE2(PPC2_DFP, QEMU_PPC_FEATURE_HAS_DFP);
8660e019746STom Musta     GET_FEATURE2(PPC2_VSX, QEMU_PPC_FEATURE_HAS_VSX);
8670e019746STom Musta     GET_FEATURE2((PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 |
8680e019746STom Musta                   PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206),
8690e019746STom Musta                   QEMU_PPC_FEATURE_ARCH_2_06);
870df84e4f3SNathan Froyd #undef GET_FEATURE
8710e019746STom Musta #undef GET_FEATURE2
872df84e4f3SNathan Froyd 
873df84e4f3SNathan Froyd     return features;
874df84e4f3SNathan Froyd }
875df84e4f3SNathan Froyd 
876a60438ddSTom Musta #define ELF_HWCAP2 get_elf_hwcap2()
877a60438ddSTom Musta 
878a60438ddSTom Musta static uint32_t get_elf_hwcap2(void)
879a60438ddSTom Musta {
880a60438ddSTom Musta     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
881a60438ddSTom Musta     uint32_t features = 0;
882a60438ddSTom Musta 
883a60438ddSTom Musta #define GET_FEATURE(flag, feature)                                      \
884a60438ddSTom Musta     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
885a60438ddSTom Musta #define GET_FEATURE2(flag, feature)                                      \
886a60438ddSTom Musta     do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
887a60438ddSTom Musta 
888a60438ddSTom Musta     GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL);
889a60438ddSTom Musta     GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR);
890a60438ddSTom Musta     GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
89124c373ecSLaurent Vivier                   PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07 |
89224c373ecSLaurent Vivier                   QEMU_PPC_FEATURE2_VEC_CRYPTO);
89324c373ecSLaurent Vivier     GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 |
8948a589aebSKhem Raj                  QEMU_PPC_FEATURE2_DARN | QEMU_PPC_FEATURE2_HAS_IEEE128);
89596c343ccSJoel Stanley     GET_FEATURE2(PPC2_ISA310, QEMU_PPC_FEATURE2_ARCH_3_1 |
89696c343ccSJoel Stanley                  QEMU_PPC_FEATURE2_MMA);
897a60438ddSTom Musta 
898a60438ddSTom Musta #undef GET_FEATURE
899a60438ddSTom Musta #undef GET_FEATURE2
900a60438ddSTom Musta 
901a60438ddSTom Musta     return features;
902a60438ddSTom Musta }
903a60438ddSTom Musta 
904f5155289Sbellard /*
905f5155289Sbellard  * The requirements here are:
906f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
907f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
908f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
909f5155289Sbellard  *   AT_IGNOREPPC is used for that.
910f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
911f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
912f5155289Sbellard  */
9130bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
914f5155289Sbellard #define ARCH_DLINFO                                     \
915f5155289Sbellard     do {                                                \
916623e250aSTom Musta         PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);              \
917f5155289Sbellard         /*                                              \
91882991bedSPeter Maydell          * Handle glibc compatibility: these magic entries must \
91982991bedSPeter Maydell          * be at the lowest addresses in the final auxv.        \
920f5155289Sbellard          */                                             \
9210bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
9220bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
92382991bedSPeter Maydell         NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
92482991bedSPeter Maydell         NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
92582991bedSPeter Maydell         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                 \
926f5155289Sbellard     } while (0)
927f5155289Sbellard 
92867867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
92967867308Sbellard {
93067867308Sbellard     _regs->gpr[1] = infop->start_stack;
93174154d7eSThomas Huth #if defined(TARGET_PPC64)
932d90b94cdSDoug Kwan     if (get_ppc64_abi(infop) < 2) {
9332ccf97ecSPeter Maydell         uint64_t val;
9342ccf97ecSPeter Maydell         get_user_u64(val, infop->entry + 8);
9352ccf97ecSPeter Maydell         _regs->gpr[2] = val + infop->load_bias;
9362ccf97ecSPeter Maydell         get_user_u64(val, infop->entry);
9372ccf97ecSPeter Maydell         infop->entry = val + infop->load_bias;
938d90b94cdSDoug Kwan     } else {
939d90b94cdSDoug Kwan         _regs->gpr[12] = infop->entry;  /* r12 set to global entry address */
940d90b94cdSDoug Kwan     }
94184409ddbSj_mayer #endif
94267867308Sbellard     _regs->nip = infop->entry;
94367867308Sbellard }
94467867308Sbellard 
945e2f3e741SNathan Froyd /* See linux kernel: arch/powerpc/include/asm/elf.h.  */
946e2f3e741SNathan Froyd #define ELF_NREG 48
947e2f3e741SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
948e2f3e741SNathan Froyd 
94905390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *env)
950e2f3e741SNathan Froyd {
951e2f3e741SNathan Froyd     int i;
952e2f3e741SNathan Froyd     target_ulong ccr = 0;
953e2f3e741SNathan Froyd 
954e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
95586cd7b2dSPaolo Bonzini         (*regs)[i] = tswapreg(env->gpr[i]);
956e2f3e741SNathan Froyd     }
957e2f3e741SNathan Froyd 
95886cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->nip);
95986cd7b2dSPaolo Bonzini     (*regs)[33] = tswapreg(env->msr);
96086cd7b2dSPaolo Bonzini     (*regs)[35] = tswapreg(env->ctr);
96186cd7b2dSPaolo Bonzini     (*regs)[36] = tswapreg(env->lr);
96210de0521SMatheus Ferst     (*regs)[37] = tswapreg(cpu_read_xer(env));
963e2f3e741SNathan Froyd 
964e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
965e2f3e741SNathan Froyd         ccr |= env->crf[i] << (32 - ((i + 1) * 4));
966e2f3e741SNathan Froyd     }
96786cd7b2dSPaolo Bonzini     (*regs)[38] = tswapreg(ccr);
968e2f3e741SNathan Froyd }
969e2f3e741SNathan Froyd 
970e2f3e741SNathan Froyd #define USE_ELF_CORE_DUMP
97167867308Sbellard #define ELF_EXEC_PAGESIZE       4096
97267867308Sbellard 
97367867308Sbellard #endif
97467867308Sbellard 
9753418fe25SSong Gao #ifdef TARGET_LOONGARCH64
9763418fe25SSong Gao 
9773418fe25SSong Gao #define ELF_START_MMAP 0x80000000
9783418fe25SSong Gao 
9793418fe25SSong Gao #define ELF_CLASS   ELFCLASS64
9803418fe25SSong Gao #define ELF_ARCH    EM_LOONGARCH
981872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
9823418fe25SSong Gao 
9833418fe25SSong Gao #define elf_check_arch(x) ((x) == EM_LOONGARCH)
9843418fe25SSong Gao 
9853418fe25SSong Gao static inline void init_thread(struct target_pt_regs *regs,
9863418fe25SSong Gao                                struct image_info *infop)
9873418fe25SSong Gao {
9883418fe25SSong Gao     /*Set crmd PG,DA = 1,0 */
9893418fe25SSong Gao     regs->csr.crmd = 2 << 3;
9903418fe25SSong Gao     regs->csr.era = infop->entry;
9913418fe25SSong Gao     regs->regs[3] = infop->start_stack;
9923418fe25SSong Gao }
9933418fe25SSong Gao 
9943418fe25SSong Gao /* See linux kernel: arch/loongarch/include/asm/elf.h */
9953418fe25SSong Gao #define ELF_NREG 45
9963418fe25SSong Gao typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
9973418fe25SSong Gao 
9983418fe25SSong Gao enum {
9993418fe25SSong Gao     TARGET_EF_R0 = 0,
10003418fe25SSong Gao     TARGET_EF_CSR_ERA = TARGET_EF_R0 + 33,
10013418fe25SSong Gao     TARGET_EF_CSR_BADV = TARGET_EF_R0 + 34,
10023418fe25SSong Gao };
10033418fe25SSong Gao 
10043418fe25SSong Gao static void elf_core_copy_regs(target_elf_gregset_t *regs,
10053418fe25SSong Gao                                const CPULoongArchState *env)
10063418fe25SSong Gao {
10073418fe25SSong Gao     int i;
10083418fe25SSong Gao 
10093418fe25SSong Gao     (*regs)[TARGET_EF_R0] = 0;
10103418fe25SSong Gao 
10113418fe25SSong Gao     for (i = 1; i < ARRAY_SIZE(env->gpr); i++) {
10123418fe25SSong Gao         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->gpr[i]);
10133418fe25SSong Gao     }
10143418fe25SSong Gao 
10153418fe25SSong Gao     (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->pc);
10163418fe25SSong Gao     (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV);
10173418fe25SSong Gao }
10183418fe25SSong Gao 
10193418fe25SSong Gao #define USE_ELF_CORE_DUMP
10203418fe25SSong Gao #define ELF_EXEC_PAGESIZE        4096
10213418fe25SSong Gao 
10223418fe25SSong Gao #define ELF_HWCAP get_elf_hwcap()
10233418fe25SSong Gao 
10243418fe25SSong Gao /* See arch/loongarch/include/uapi/asm/hwcap.h */
10253418fe25SSong Gao enum {
10263418fe25SSong Gao     HWCAP_LOONGARCH_CPUCFG   = (1 << 0),
10273418fe25SSong Gao     HWCAP_LOONGARCH_LAM      = (1 << 1),
10283418fe25SSong Gao     HWCAP_LOONGARCH_UAL      = (1 << 2),
10293418fe25SSong Gao     HWCAP_LOONGARCH_FPU      = (1 << 3),
10303418fe25SSong Gao     HWCAP_LOONGARCH_LSX      = (1 << 4),
10313418fe25SSong Gao     HWCAP_LOONGARCH_LASX     = (1 << 5),
10323418fe25SSong Gao     HWCAP_LOONGARCH_CRC32    = (1 << 6),
10333418fe25SSong Gao     HWCAP_LOONGARCH_COMPLEX  = (1 << 7),
10343418fe25SSong Gao     HWCAP_LOONGARCH_CRYPTO   = (1 << 8),
10353418fe25SSong Gao     HWCAP_LOONGARCH_LVZ      = (1 << 9),
10363418fe25SSong Gao     HWCAP_LOONGARCH_LBT_X86  = (1 << 10),
10373418fe25SSong Gao     HWCAP_LOONGARCH_LBT_ARM  = (1 << 11),
10383418fe25SSong Gao     HWCAP_LOONGARCH_LBT_MIPS = (1 << 12),
10393418fe25SSong Gao };
10403418fe25SSong Gao 
10413418fe25SSong Gao static uint32_t get_elf_hwcap(void)
10423418fe25SSong Gao {
10433418fe25SSong Gao     LoongArchCPU *cpu = LOONGARCH_CPU(thread_cpu);
10443418fe25SSong Gao     uint32_t hwcaps = 0;
10453418fe25SSong Gao 
10463418fe25SSong Gao     hwcaps |= HWCAP_LOONGARCH_CRC32;
10473418fe25SSong Gao 
10483418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[1], CPUCFG1, UAL)) {
10493418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_UAL;
10503418fe25SSong Gao     }
10513418fe25SSong Gao 
10523418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, FP)) {
10533418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_FPU;
10543418fe25SSong Gao     }
10553418fe25SSong Gao 
10563418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LAM)) {
10573418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_LAM;
10583418fe25SSong Gao     }
10593418fe25SSong Gao 
10603418fe25SSong Gao     return hwcaps;
10613418fe25SSong Gao }
10623418fe25SSong Gao 
10633418fe25SSong Gao #define ELF_PLATFORM "loongarch"
10643418fe25SSong Gao 
10653418fe25SSong Gao #endif /* TARGET_LOONGARCH64 */
10663418fe25SSong Gao 
1067048f6b4dSbellard #ifdef TARGET_MIPS
1068048f6b4dSbellard 
1069048f6b4dSbellard #define ELF_START_MMAP 0x80000000
1070048f6b4dSbellard 
1071388bb21aSths #ifdef TARGET_MIPS64
1072388bb21aSths #define ELF_CLASS   ELFCLASS64
1073388bb21aSths #else
1074048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
1075388bb21aSths #endif
1076048f6b4dSbellard #define ELF_ARCH    EM_MIPS
1077872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
1078048f6b4dSbellard 
1079ace3d654SCarlo Marcelo Arenas Belón #ifdef TARGET_ABI_MIPSN32
1080ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) ((x) & EF_MIPS_ABI2)
1081ace3d654SCarlo Marcelo Arenas Belón #else
1082ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (!((x) & EF_MIPS_ABI2))
1083ace3d654SCarlo Marcelo Arenas Belón #endif
1084ace3d654SCarlo Marcelo Arenas Belón 
1085fbf47c18SJiaxun Yang #define ELF_BASE_PLATFORM get_elf_base_platform()
1086fbf47c18SJiaxun Yang 
1087fbf47c18SJiaxun Yang #define MATCH_PLATFORM_INSN(_flags, _base_platform)      \
1088fbf47c18SJiaxun Yang     do { if ((cpu->env.insn_flags & (_flags)) == _flags) \
1089fbf47c18SJiaxun Yang     { return _base_platform; } } while (0)
1090fbf47c18SJiaxun Yang 
1091fbf47c18SJiaxun Yang static const char *get_elf_base_platform(void)
1092fbf47c18SJiaxun Yang {
1093fbf47c18SJiaxun Yang     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
1094fbf47c18SJiaxun Yang 
1095fbf47c18SJiaxun Yang     /* 64 bit ISAs goes first */
1096fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R6, "mips64r6");
1097fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R5, "mips64r5");
1098fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R2, "mips64r2");
1099fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R1, "mips64");
1100fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS5, "mips5");
1101fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS4, "mips4");
1102fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS3, "mips3");
1103fbf47c18SJiaxun Yang 
1104fbf47c18SJiaxun Yang     /* 32 bit ISAs */
1105fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R6, "mips32r6");
1106fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R5, "mips32r5");
1107fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R2, "mips32r2");
1108fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R1, "mips32");
1109fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS2, "mips2");
1110fbf47c18SJiaxun Yang 
1111fbf47c18SJiaxun Yang     /* Fallback */
1112fbf47c18SJiaxun Yang     return "mips";
1113fbf47c18SJiaxun Yang }
1114fbf47c18SJiaxun Yang #undef MATCH_PLATFORM_INSN
1115fbf47c18SJiaxun Yang 
1116d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1117d97ef72eSRichard Henderson                                struct image_info *infop)
1118048f6b4dSbellard {
1119623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
1120048f6b4dSbellard     regs->cp0_epc = infop->entry;
1121048f6b4dSbellard     regs->regs[29] = infop->start_stack;
1122048f6b4dSbellard }
1123048f6b4dSbellard 
112451e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/elf.h.  */
112551e52606SNathan Froyd #define ELF_NREG 45
112651e52606SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
112751e52606SNathan Froyd 
112851e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/reg.h.  */
112951e52606SNathan Froyd enum {
113051e52606SNathan Froyd #ifdef TARGET_MIPS64
113151e52606SNathan Froyd     TARGET_EF_R0 = 0,
113251e52606SNathan Froyd #else
113351e52606SNathan Froyd     TARGET_EF_R0 = 6,
113451e52606SNathan Froyd #endif
113551e52606SNathan Froyd     TARGET_EF_R26 = TARGET_EF_R0 + 26,
113651e52606SNathan Froyd     TARGET_EF_R27 = TARGET_EF_R0 + 27,
113751e52606SNathan Froyd     TARGET_EF_LO = TARGET_EF_R0 + 32,
113851e52606SNathan Froyd     TARGET_EF_HI = TARGET_EF_R0 + 33,
113951e52606SNathan Froyd     TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
114051e52606SNathan Froyd     TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
114151e52606SNathan Froyd     TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
114251e52606SNathan Froyd     TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
114351e52606SNathan Froyd };
114451e52606SNathan Froyd 
114551e52606SNathan Froyd /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
114605390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMIPSState *env)
114751e52606SNathan Froyd {
114851e52606SNathan Froyd     int i;
114951e52606SNathan Froyd 
115051e52606SNathan Froyd     for (i = 0; i < TARGET_EF_R0; i++) {
115151e52606SNathan Froyd         (*regs)[i] = 0;
115251e52606SNathan Froyd     }
115351e52606SNathan Froyd     (*regs)[TARGET_EF_R0] = 0;
115451e52606SNathan Froyd 
115551e52606SNathan Froyd     for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
1156a29f998dSPaolo Bonzini         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]);
115751e52606SNathan Froyd     }
115851e52606SNathan Froyd 
115951e52606SNathan Froyd     (*regs)[TARGET_EF_R26] = 0;
116051e52606SNathan Froyd     (*regs)[TARGET_EF_R27] = 0;
1161a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_LO] = tswapreg(env->active_tc.LO[0]);
1162a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_HI] = tswapreg(env->active_tc.HI[0]);
1163a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_EPC] = tswapreg(env->active_tc.PC);
1164a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_BADVADDR] = tswapreg(env->CP0_BadVAddr);
1165a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_STATUS] = tswapreg(env->CP0_Status);
1166a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_CAUSE] = tswapreg(env->CP0_Cause);
116751e52606SNathan Froyd }
116851e52606SNathan Froyd 
116951e52606SNathan Froyd #define USE_ELF_CORE_DUMP
1170388bb21aSths #define ELF_EXEC_PAGESIZE        4096
1171388bb21aSths 
117246a1ee4fSJames Cowgill /* See arch/mips/include/uapi/asm/hwcap.h.  */
117346a1ee4fSJames Cowgill enum {
117446a1ee4fSJames Cowgill     HWCAP_MIPS_R6           = (1 << 0),
117546a1ee4fSJames Cowgill     HWCAP_MIPS_MSA          = (1 << 1),
11769ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_CRC32        = (1 << 2),
11779ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16       = (1 << 3),
11789ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MDMX         = (1 << 4),
11799ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS3D       = (1 << 5),
11809ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_SMARTMIPS    = (1 << 6),
11819ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP          = (1 << 7),
11829ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP2         = (1 << 8),
11839ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP3         = (1 << 9),
11849ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16E2     = (1 << 10),
11859ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_MMI      = (1 << 11),
11869ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT      = (1 << 12),
11879ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT2     = (1 << 13),
11889ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_CPUCFG   = (1 << 14),
118946a1ee4fSJames Cowgill };
119046a1ee4fSJames Cowgill 
119146a1ee4fSJames Cowgill #define ELF_HWCAP get_elf_hwcap()
119246a1ee4fSJames Cowgill 
11937d9a3d96SPhilippe Mathieu-Daudé #define GET_FEATURE_INSN(_flag, _hwcap) \
11946dd97bfcSPhilippe Mathieu-Daudé     do { if (cpu->env.insn_flags & (_flag)) { hwcaps |= _hwcap; } } while (0)
11956dd97bfcSPhilippe Mathieu-Daudé 
1196388765a0SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_SET(_reg, _mask, _hwcap) \
1197388765a0SPhilippe Mathieu-Daudé     do { if (cpu->env._reg & (_mask)) { hwcaps |= _hwcap; } } while (0)
1198388765a0SPhilippe Mathieu-Daudé 
1199ce543844SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_EQU(_reg, _start, _length, _val, _hwcap) \
1200ce543844SPhilippe Mathieu-Daudé     do { \
1201ce543844SPhilippe Mathieu-Daudé         if (extract32(cpu->env._reg, (_start), (_length)) == (_val)) { \
1202ce543844SPhilippe Mathieu-Daudé             hwcaps |= _hwcap; \
1203ce543844SPhilippe Mathieu-Daudé         } \
1204ce543844SPhilippe Mathieu-Daudé     } while (0)
1205ce543844SPhilippe Mathieu-Daudé 
120646a1ee4fSJames Cowgill static uint32_t get_elf_hwcap(void)
120746a1ee4fSJames Cowgill {
120846a1ee4fSJames Cowgill     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
120946a1ee4fSJames Cowgill     uint32_t hwcaps = 0;
121046a1ee4fSJames Cowgill 
1211ce543844SPhilippe Mathieu-Daudé     GET_FEATURE_REG_EQU(CP0_Config0, CP0C0_AR, CP0C0_AR_LENGTH,
1212ce543844SPhilippe Mathieu-Daudé                         2, HWCAP_MIPS_R6);
1213388765a0SPhilippe Mathieu-Daudé     GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA);
121453673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LMMI, HWCAP_LOONGSON_MMI);
121553673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LEXT, HWCAP_LOONGSON_EXT);
121646a1ee4fSJames Cowgill 
121746a1ee4fSJames Cowgill     return hwcaps;
121846a1ee4fSJames Cowgill }
121946a1ee4fSJames Cowgill 
1220ce543844SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_EQU
1221388765a0SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_SET
12227d9a3d96SPhilippe Mathieu-Daudé #undef GET_FEATURE_INSN
12236dd97bfcSPhilippe Mathieu-Daudé 
1224048f6b4dSbellard #endif /* TARGET_MIPS */
1225048f6b4dSbellard 
1226b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
1227b779e29eSEdgar E. Iglesias 
1228b779e29eSEdgar E. Iglesias #define ELF_START_MMAP 0x80000000
1229b779e29eSEdgar E. Iglesias 
12300d5d4699SEdgar E. Iglesias #define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
1231b779e29eSEdgar E. Iglesias 
1232b779e29eSEdgar E. Iglesias #define ELF_CLASS   ELFCLASS32
12330d5d4699SEdgar E. Iglesias #define ELF_ARCH    EM_MICROBLAZE
1234b779e29eSEdgar E. Iglesias 
1235d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1236d97ef72eSRichard Henderson                                struct image_info *infop)
1237b779e29eSEdgar E. Iglesias {
1238b779e29eSEdgar E. Iglesias     regs->pc = infop->entry;
1239b779e29eSEdgar E. Iglesias     regs->r1 = infop->start_stack;
1240b779e29eSEdgar E. Iglesias 
1241b779e29eSEdgar E. Iglesias }
1242b779e29eSEdgar E. Iglesias 
1243b779e29eSEdgar E. Iglesias #define ELF_EXEC_PAGESIZE        4096
1244b779e29eSEdgar E. Iglesias 
1245e4cbd44dSEdgar E. Iglesias #define USE_ELF_CORE_DUMP
1246e4cbd44dSEdgar E. Iglesias #define ELF_NREG 38
1247e4cbd44dSEdgar E. Iglesias typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1248e4cbd44dSEdgar E. Iglesias 
1249e4cbd44dSEdgar E. Iglesias /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
125005390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env)
1251e4cbd44dSEdgar E. Iglesias {
1252e4cbd44dSEdgar E. Iglesias     int i, pos = 0;
1253e4cbd44dSEdgar E. Iglesias 
1254e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 32; i++) {
125586cd7b2dSPaolo Bonzini         (*regs)[pos++] = tswapreg(env->regs[i]);
1256e4cbd44dSEdgar E. Iglesias     }
1257e4cbd44dSEdgar E. Iglesias 
1258af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->pc);
12591074c0fbSRichard Henderson     (*regs)[pos++] = tswapreg(mb_cpu_read_msr(env));
1260af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1261af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->ear);
1262af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1263af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->esr);
1264e4cbd44dSEdgar E. Iglesias }
1265e4cbd44dSEdgar E. Iglesias 
1266b779e29eSEdgar E. Iglesias #endif /* TARGET_MICROBLAZE */
1267b779e29eSEdgar E. Iglesias 
1268a0a839b6SMarek Vasut #ifdef TARGET_NIOS2
1269a0a839b6SMarek Vasut 
1270a0a839b6SMarek Vasut #define ELF_START_MMAP 0x80000000
1271a0a839b6SMarek Vasut 
1272a0a839b6SMarek Vasut #define elf_check_arch(x) ((x) == EM_ALTERA_NIOS2)
1273a0a839b6SMarek Vasut 
1274a0a839b6SMarek Vasut #define ELF_CLASS   ELFCLASS32
1275a0a839b6SMarek Vasut #define ELF_ARCH    EM_ALTERA_NIOS2
1276a0a839b6SMarek Vasut 
1277a0a839b6SMarek Vasut static void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1278a0a839b6SMarek Vasut {
1279a0a839b6SMarek Vasut     regs->ea = infop->entry;
1280a0a839b6SMarek Vasut     regs->sp = infop->start_stack;
1281a0a839b6SMarek Vasut }
1282a0a839b6SMarek Vasut 
1283f5ef0e51SRichard Henderson #define LO_COMMPAGE  TARGET_PAGE_SIZE
1284f5ef0e51SRichard Henderson 
1285f5ef0e51SRichard Henderson static bool init_guest_commpage(void)
1286f5ef0e51SRichard Henderson {
1287f5ef0e51SRichard Henderson     static const uint8_t kuser_page[4 + 2 * 64] = {
1288f5ef0e51SRichard Henderson         /* __kuser_helper_version */
1289f5ef0e51SRichard Henderson         [0x00] = 0x02, 0x00, 0x00, 0x00,
1290f5ef0e51SRichard Henderson 
1291f5ef0e51SRichard Henderson         /* __kuser_cmpxchg */
1292f5ef0e51SRichard Henderson         [0x04] = 0x3a, 0x6c, 0x3b, 0x00,  /* trap 16 */
1293f5ef0e51SRichard Henderson                  0x3a, 0x28, 0x00, 0xf8,  /* ret */
1294f5ef0e51SRichard Henderson 
1295f5ef0e51SRichard Henderson         /* __kuser_sigtramp */
1296f5ef0e51SRichard Henderson         [0x44] = 0xc4, 0x22, 0x80, 0x00,  /* movi r2, __NR_rt_sigreturn */
1297f5ef0e51SRichard Henderson                  0x3a, 0x68, 0x3b, 0x00,  /* trap 0 */
1298f5ef0e51SRichard Henderson     };
1299f5ef0e51SRichard Henderson 
1300f5ef0e51SRichard Henderson     void *want = g2h_untagged(LO_COMMPAGE & -qemu_host_page_size);
1301f5ef0e51SRichard Henderson     void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
1302f5ef0e51SRichard Henderson                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1303f5ef0e51SRichard Henderson 
1304f5ef0e51SRichard Henderson     if (addr == MAP_FAILED) {
1305f5ef0e51SRichard Henderson         perror("Allocating guest commpage");
1306f5ef0e51SRichard Henderson         exit(EXIT_FAILURE);
1307f5ef0e51SRichard Henderson     }
1308f5ef0e51SRichard Henderson     if (addr != want) {
1309f5ef0e51SRichard Henderson         return false;
1310f5ef0e51SRichard Henderson     }
1311f5ef0e51SRichard Henderson 
1312f5ef0e51SRichard Henderson     memcpy(addr, kuser_page, sizeof(kuser_page));
1313f5ef0e51SRichard Henderson 
1314f5ef0e51SRichard Henderson     if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
1315f5ef0e51SRichard Henderson         perror("Protecting guest commpage");
1316f5ef0e51SRichard Henderson         exit(EXIT_FAILURE);
1317f5ef0e51SRichard Henderson     }
1318f5ef0e51SRichard Henderson 
1319*49840a4aSRichard Henderson     page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
1320f5ef0e51SRichard Henderson                    PAGE_READ | PAGE_EXEC | PAGE_VALID);
1321f5ef0e51SRichard Henderson     return true;
1322f5ef0e51SRichard Henderson }
1323f5ef0e51SRichard Henderson 
1324a0a839b6SMarek Vasut #define ELF_EXEC_PAGESIZE        4096
1325a0a839b6SMarek Vasut 
1326a0a839b6SMarek Vasut #define USE_ELF_CORE_DUMP
1327a0a839b6SMarek Vasut #define ELF_NREG 49
1328a0a839b6SMarek Vasut typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1329a0a839b6SMarek Vasut 
1330a0a839b6SMarek Vasut /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
1331a0a839b6SMarek Vasut static void elf_core_copy_regs(target_elf_gregset_t *regs,
1332a0a839b6SMarek Vasut                                const CPUNios2State *env)
1333a0a839b6SMarek Vasut {
1334a0a839b6SMarek Vasut     int i;
1335a0a839b6SMarek Vasut 
1336a0a839b6SMarek Vasut     (*regs)[0] = -1;
1337a0a839b6SMarek Vasut     for (i = 1; i < 8; i++)    /* r0-r7 */
1338a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1339a0a839b6SMarek Vasut 
1340a0a839b6SMarek Vasut     for (i = 8; i < 16; i++)   /* r8-r15 */
1341a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i - 8]);
1342a0a839b6SMarek Vasut 
1343a0a839b6SMarek Vasut     for (i = 16; i < 24; i++)  /* r16-r23 */
1344a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1345a0a839b6SMarek Vasut     (*regs)[24] = -1;    /* R_ET */
1346a0a839b6SMarek Vasut     (*regs)[25] = -1;    /* R_BT */
1347a0a839b6SMarek Vasut     (*regs)[26] = tswapreg(env->regs[R_GP]);
1348a0a839b6SMarek Vasut     (*regs)[27] = tswapreg(env->regs[R_SP]);
1349a0a839b6SMarek Vasut     (*regs)[28] = tswapreg(env->regs[R_FP]);
1350a0a839b6SMarek Vasut     (*regs)[29] = tswapreg(env->regs[R_EA]);
1351a0a839b6SMarek Vasut     (*regs)[30] = -1;    /* R_SSTATUS */
1352a0a839b6SMarek Vasut     (*regs)[31] = tswapreg(env->regs[R_RA]);
1353a0a839b6SMarek Vasut 
135417a406eeSRichard Henderson     (*regs)[32] = tswapreg(env->pc);
1355a0a839b6SMarek Vasut 
1356a0a839b6SMarek Vasut     (*regs)[33] = -1; /* R_STATUS */
1357a0a839b6SMarek Vasut     (*regs)[34] = tswapreg(env->regs[CR_ESTATUS]);
1358a0a839b6SMarek Vasut 
1359a0a839b6SMarek Vasut     for (i = 35; i < 49; i++)    /* ... */
1360a0a839b6SMarek Vasut         (*regs)[i] = -1;
1361a0a839b6SMarek Vasut }
1362a0a839b6SMarek Vasut 
1363a0a839b6SMarek Vasut #endif /* TARGET_NIOS2 */
1364a0a839b6SMarek Vasut 
1365d962783eSJia Liu #ifdef TARGET_OPENRISC
1366d962783eSJia Liu 
1367d962783eSJia Liu #define ELF_START_MMAP 0x08000000
1368d962783eSJia Liu 
1369d962783eSJia Liu #define ELF_ARCH EM_OPENRISC
1370d962783eSJia Liu #define ELF_CLASS ELFCLASS32
1371d962783eSJia Liu #define ELF_DATA  ELFDATA2MSB
1372d962783eSJia Liu 
1373d962783eSJia Liu static inline void init_thread(struct target_pt_regs *regs,
1374d962783eSJia Liu                                struct image_info *infop)
1375d962783eSJia Liu {
1376d962783eSJia Liu     regs->pc = infop->entry;
1377d962783eSJia Liu     regs->gpr[1] = infop->start_stack;
1378d962783eSJia Liu }
1379d962783eSJia Liu 
1380d962783eSJia Liu #define USE_ELF_CORE_DUMP
1381d962783eSJia Liu #define ELF_EXEC_PAGESIZE 8192
1382d962783eSJia Liu 
1383d962783eSJia Liu /* See linux kernel arch/openrisc/include/asm/elf.h.  */
1384d962783eSJia Liu #define ELF_NREG 34 /* gprs and pc, sr */
1385d962783eSJia Liu typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1386d962783eSJia Liu 
1387d962783eSJia Liu static void elf_core_copy_regs(target_elf_gregset_t *regs,
1388d962783eSJia Liu                                const CPUOpenRISCState *env)
1389d962783eSJia Liu {
1390d962783eSJia Liu     int i;
1391d962783eSJia Liu 
1392d962783eSJia Liu     for (i = 0; i < 32; i++) {
1393d89e71e8SStafford Horne         (*regs)[i] = tswapreg(cpu_get_gpr(env, i));
1394d962783eSJia Liu     }
139586cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->pc);
139684775c43SRichard Henderson     (*regs)[33] = tswapreg(cpu_get_sr(env));
1397d962783eSJia Liu }
1398d962783eSJia Liu #define ELF_HWCAP 0
1399d962783eSJia Liu #define ELF_PLATFORM NULL
1400d962783eSJia Liu 
1401d962783eSJia Liu #endif /* TARGET_OPENRISC */
1402d962783eSJia Liu 
1403fdf9b3e8Sbellard #ifdef TARGET_SH4
1404fdf9b3e8Sbellard 
1405fdf9b3e8Sbellard #define ELF_START_MMAP 0x80000000
1406fdf9b3e8Sbellard 
1407fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
1408fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
1409fdf9b3e8Sbellard 
1410d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1411d97ef72eSRichard Henderson                                struct image_info *infop)
1412fdf9b3e8Sbellard {
1413fdf9b3e8Sbellard     /* Check other registers XXXXX */
1414fdf9b3e8Sbellard     regs->pc = infop->entry;
1415072ae847Sths     regs->regs[15] = infop->start_stack;
1416fdf9b3e8Sbellard }
1417fdf9b3e8Sbellard 
14187631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/elf.h.  */
14197631c97eSNathan Froyd #define ELF_NREG 23
14207631c97eSNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
14217631c97eSNathan Froyd 
14227631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/ptrace.h.  */
14237631c97eSNathan Froyd enum {
14247631c97eSNathan Froyd     TARGET_REG_PC = 16,
14257631c97eSNathan Froyd     TARGET_REG_PR = 17,
14267631c97eSNathan Froyd     TARGET_REG_SR = 18,
14277631c97eSNathan Froyd     TARGET_REG_GBR = 19,
14287631c97eSNathan Froyd     TARGET_REG_MACH = 20,
14297631c97eSNathan Froyd     TARGET_REG_MACL = 21,
14307631c97eSNathan Froyd     TARGET_REG_SYSCALL = 22
14317631c97eSNathan Froyd };
14327631c97eSNathan Froyd 
1433d97ef72eSRichard Henderson static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
143405390248SAndreas Färber                                       const CPUSH4State *env)
14357631c97eSNathan Froyd {
14367631c97eSNathan Froyd     int i;
14377631c97eSNathan Froyd 
14387631c97eSNathan Froyd     for (i = 0; i < 16; i++) {
143972cd500bSPhilippe Mathieu-Daudé         (*regs)[i] = tswapreg(env->gregs[i]);
14407631c97eSNathan Froyd     }
14417631c97eSNathan Froyd 
144286cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
144386cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PR] = tswapreg(env->pr);
144486cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_SR] = tswapreg(env->sr);
144586cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_GBR] = tswapreg(env->gbr);
144686cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACH] = tswapreg(env->mach);
144786cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACL] = tswapreg(env->macl);
14487631c97eSNathan Froyd     (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
14497631c97eSNathan Froyd }
14507631c97eSNathan Froyd 
14517631c97eSNathan Froyd #define USE_ELF_CORE_DUMP
1452fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
1453fdf9b3e8Sbellard 
1454e42fd944SRichard Henderson enum {
1455e42fd944SRichard Henderson     SH_CPU_HAS_FPU            = 0x0001, /* Hardware FPU support */
1456e42fd944SRichard Henderson     SH_CPU_HAS_P2_FLUSH_BUG   = 0x0002, /* Need to flush the cache in P2 area */
1457e42fd944SRichard Henderson     SH_CPU_HAS_MMU_PAGE_ASSOC = 0x0004, /* SH3: TLB way selection bit support */
1458e42fd944SRichard Henderson     SH_CPU_HAS_DSP            = 0x0008, /* SH-DSP: DSP support */
1459e42fd944SRichard Henderson     SH_CPU_HAS_PERF_COUNTER   = 0x0010, /* Hardware performance counters */
1460e42fd944SRichard Henderson     SH_CPU_HAS_PTEA           = 0x0020, /* PTEA register */
1461e42fd944SRichard Henderson     SH_CPU_HAS_LLSC           = 0x0040, /* movli.l/movco.l */
1462e42fd944SRichard Henderson     SH_CPU_HAS_L2_CACHE       = 0x0080, /* Secondary cache / URAM */
1463e42fd944SRichard Henderson     SH_CPU_HAS_OP32           = 0x0100, /* 32-bit instruction support */
1464e42fd944SRichard Henderson     SH_CPU_HAS_PTEAEX         = 0x0200, /* PTE ASID Extension support */
1465e42fd944SRichard Henderson };
1466e42fd944SRichard Henderson 
1467e42fd944SRichard Henderson #define ELF_HWCAP get_elf_hwcap()
1468e42fd944SRichard Henderson 
1469e42fd944SRichard Henderson static uint32_t get_elf_hwcap(void)
1470e42fd944SRichard Henderson {
1471e42fd944SRichard Henderson     SuperHCPU *cpu = SUPERH_CPU(thread_cpu);
1472e42fd944SRichard Henderson     uint32_t hwcap = 0;
1473e42fd944SRichard Henderson 
1474e42fd944SRichard Henderson     hwcap |= SH_CPU_HAS_FPU;
1475e42fd944SRichard Henderson 
1476e42fd944SRichard Henderson     if (cpu->env.features & SH_FEATURE_SH4A) {
1477e42fd944SRichard Henderson         hwcap |= SH_CPU_HAS_LLSC;
1478e42fd944SRichard Henderson     }
1479e42fd944SRichard Henderson 
1480e42fd944SRichard Henderson     return hwcap;
1481e42fd944SRichard Henderson }
1482e42fd944SRichard Henderson 
1483fdf9b3e8Sbellard #endif
1484fdf9b3e8Sbellard 
148548733d19Sths #ifdef TARGET_CRIS
148648733d19Sths 
148748733d19Sths #define ELF_START_MMAP 0x80000000
148848733d19Sths 
148948733d19Sths #define ELF_CLASS ELFCLASS32
149048733d19Sths #define ELF_ARCH  EM_CRIS
149148733d19Sths 
1492d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1493d97ef72eSRichard Henderson                                struct image_info *infop)
149448733d19Sths {
149548733d19Sths     regs->erp = infop->entry;
149648733d19Sths }
149748733d19Sths 
149848733d19Sths #define ELF_EXEC_PAGESIZE        8192
149948733d19Sths 
150048733d19Sths #endif
150148733d19Sths 
1502e6e5906bSpbrook #ifdef TARGET_M68K
1503e6e5906bSpbrook 
1504e6e5906bSpbrook #define ELF_START_MMAP 0x80000000
1505e6e5906bSpbrook 
1506e6e5906bSpbrook #define ELF_CLASS       ELFCLASS32
1507e6e5906bSpbrook #define ELF_ARCH        EM_68K
1508e6e5906bSpbrook 
1509e6e5906bSpbrook /* ??? Does this need to do anything?
1510e6e5906bSpbrook    #define ELF_PLAT_INIT(_r) */
1511e6e5906bSpbrook 
1512d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1513d97ef72eSRichard Henderson                                struct image_info *infop)
1514e6e5906bSpbrook {
1515e6e5906bSpbrook     regs->usp = infop->start_stack;
1516e6e5906bSpbrook     regs->sr = 0;
1517e6e5906bSpbrook     regs->pc = infop->entry;
1518e6e5906bSpbrook }
1519e6e5906bSpbrook 
15207a93cc55SNathan Froyd /* See linux kernel: arch/m68k/include/asm/elf.h.  */
15217a93cc55SNathan Froyd #define ELF_NREG 20
15227a93cc55SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
15237a93cc55SNathan Froyd 
152405390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUM68KState *env)
15257a93cc55SNathan Froyd {
152686cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->dregs[1]);
152786cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->dregs[2]);
152886cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->dregs[3]);
152986cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->dregs[4]);
153086cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->dregs[5]);
153186cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->dregs[6]);
153286cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->dregs[7]);
153386cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->aregs[0]);
153486cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->aregs[1]);
153586cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->aregs[2]);
153686cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->aregs[3]);
153786cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->aregs[4]);
153886cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->aregs[5]);
153986cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->aregs[6]);
154086cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->dregs[0]);
154186cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->aregs[7]);
154286cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(env->dregs[0]); /* FIXME: orig_d0 */
154386cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->sr);
154486cd7b2dSPaolo Bonzini     (*regs)[18] = tswapreg(env->pc);
15457a93cc55SNathan Froyd     (*regs)[19] = 0;  /* FIXME: regs->format | regs->vector */
15467a93cc55SNathan Froyd }
15477a93cc55SNathan Froyd 
15487a93cc55SNathan Froyd #define USE_ELF_CORE_DUMP
1549e6e5906bSpbrook #define ELF_EXEC_PAGESIZE       8192
1550e6e5906bSpbrook 
1551e6e5906bSpbrook #endif
1552e6e5906bSpbrook 
15537a3148a9Sj_mayer #ifdef TARGET_ALPHA
15547a3148a9Sj_mayer 
15557a3148a9Sj_mayer #define ELF_START_MMAP (0x30000000000ULL)
15567a3148a9Sj_mayer 
15577a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
15587a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
15597a3148a9Sj_mayer 
1560d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1561d97ef72eSRichard Henderson                                struct image_info *infop)
15627a3148a9Sj_mayer {
15637a3148a9Sj_mayer     regs->pc = infop->entry;
15647a3148a9Sj_mayer     regs->ps = 8;
15657a3148a9Sj_mayer     regs->usp = infop->start_stack;
15667a3148a9Sj_mayer }
15677a3148a9Sj_mayer 
15687a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
15697a3148a9Sj_mayer 
15707a3148a9Sj_mayer #endif /* TARGET_ALPHA */
15717a3148a9Sj_mayer 
1572a4c075f1SUlrich Hecht #ifdef TARGET_S390X
1573a4c075f1SUlrich Hecht 
1574a4c075f1SUlrich Hecht #define ELF_START_MMAP (0x20000000000ULL)
1575a4c075f1SUlrich Hecht 
1576a4c075f1SUlrich Hecht #define ELF_CLASS	ELFCLASS64
1577a4c075f1SUlrich Hecht #define ELF_DATA	ELFDATA2MSB
1578a4c075f1SUlrich Hecht #define ELF_ARCH	EM_S390
1579a4c075f1SUlrich Hecht 
15806d88baf1SDavid Hildenbrand #include "elf.h"
15816d88baf1SDavid Hildenbrand 
15826d88baf1SDavid Hildenbrand #define ELF_HWCAP get_elf_hwcap()
15836d88baf1SDavid Hildenbrand 
15846d88baf1SDavid Hildenbrand #define GET_FEATURE(_feat, _hwcap) \
15856d88baf1SDavid Hildenbrand     do { if (s390_has_feat(_feat)) { hwcap |= _hwcap; } } while (0)
15866d88baf1SDavid Hildenbrand 
15876d88baf1SDavid Hildenbrand static uint32_t get_elf_hwcap(void)
15886d88baf1SDavid Hildenbrand {
15896d88baf1SDavid Hildenbrand     /*
15906d88baf1SDavid Hildenbrand      * Let's assume we always have esan3 and zarch.
15916d88baf1SDavid Hildenbrand      * 31-bit processes can use 64-bit registers (high gprs).
15926d88baf1SDavid Hildenbrand      */
15936d88baf1SDavid Hildenbrand     uint32_t hwcap = HWCAP_S390_ESAN3 | HWCAP_S390_ZARCH | HWCAP_S390_HIGH_GPRS;
15946d88baf1SDavid Hildenbrand 
15956d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_STFLE, HWCAP_S390_STFLE);
15966d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_MSA, HWCAP_S390_MSA);
15976d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_LONG_DISPLACEMENT, HWCAP_S390_LDISP);
15986d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_EXTENDED_IMMEDIATE, HWCAP_S390_EIMM);
15996d88baf1SDavid Hildenbrand     if (s390_has_feat(S390_FEAT_EXTENDED_TRANSLATION_3) &&
16006d88baf1SDavid Hildenbrand         s390_has_feat(S390_FEAT_ETF3_ENH)) {
16016d88baf1SDavid Hildenbrand         hwcap |= HWCAP_S390_ETF3EH;
16026d88baf1SDavid Hildenbrand     }
16036d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS);
1604da215c23SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR_ENH, HWCAP_S390_VXRS_EXT);
16056d88baf1SDavid Hildenbrand 
16066d88baf1SDavid Hildenbrand     return hwcap;
16076d88baf1SDavid Hildenbrand }
16086d88baf1SDavid Hildenbrand 
1609a4c075f1SUlrich Hecht static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1610a4c075f1SUlrich Hecht {
1611a4c075f1SUlrich Hecht     regs->psw.addr = infop->entry;
1612a4c075f1SUlrich Hecht     regs->psw.mask = PSW_MASK_64 | PSW_MASK_32;
1613a4c075f1SUlrich Hecht     regs->gprs[15] = infop->start_stack;
1614a4c075f1SUlrich Hecht }
1615a4c075f1SUlrich Hecht 
16164a1e8931SIlya Leoshkevich /* See linux kernel: arch/s390/include/uapi/asm/ptrace.h (s390_regs).  */
16174a1e8931SIlya Leoshkevich #define ELF_NREG 27
16184a1e8931SIlya Leoshkevich typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
16194a1e8931SIlya Leoshkevich 
16204a1e8931SIlya Leoshkevich enum {
16214a1e8931SIlya Leoshkevich     TARGET_REG_PSWM = 0,
16224a1e8931SIlya Leoshkevich     TARGET_REG_PSWA = 1,
16234a1e8931SIlya Leoshkevich     TARGET_REG_GPRS = 2,
16244a1e8931SIlya Leoshkevich     TARGET_REG_ARS = 18,
16254a1e8931SIlya Leoshkevich     TARGET_REG_ORIG_R2 = 26,
16264a1e8931SIlya Leoshkevich };
16274a1e8931SIlya Leoshkevich 
16284a1e8931SIlya Leoshkevich static void elf_core_copy_regs(target_elf_gregset_t *regs,
16294a1e8931SIlya Leoshkevich                                const CPUS390XState *env)
16304a1e8931SIlya Leoshkevich {
16314a1e8931SIlya Leoshkevich     int i;
16324a1e8931SIlya Leoshkevich     uint32_t *aregs;
16334a1e8931SIlya Leoshkevich 
16344a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWM] = tswapreg(env->psw.mask);
16354a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWA] = tswapreg(env->psw.addr);
16364a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
16374a1e8931SIlya Leoshkevich         (*regs)[TARGET_REG_GPRS + i] = tswapreg(env->regs[i]);
16384a1e8931SIlya Leoshkevich     }
16394a1e8931SIlya Leoshkevich     aregs = (uint32_t *)&((*regs)[TARGET_REG_ARS]);
16404a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
16414a1e8931SIlya Leoshkevich         aregs[i] = tswap32(env->aregs[i]);
16424a1e8931SIlya Leoshkevich     }
16434a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_ORIG_R2] = 0;
16444a1e8931SIlya Leoshkevich }
16454a1e8931SIlya Leoshkevich 
16464a1e8931SIlya Leoshkevich #define USE_ELF_CORE_DUMP
16474a1e8931SIlya Leoshkevich #define ELF_EXEC_PAGESIZE 4096
16484a1e8931SIlya Leoshkevich 
1649a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
1650a4c075f1SUlrich Hecht 
165147ae93cdSMichael Clark #ifdef TARGET_RISCV
165247ae93cdSMichael Clark 
165347ae93cdSMichael Clark #define ELF_START_MMAP 0x80000000
165447ae93cdSMichael Clark #define ELF_ARCH  EM_RISCV
165547ae93cdSMichael Clark 
165647ae93cdSMichael Clark #ifdef TARGET_RISCV32
165747ae93cdSMichael Clark #define ELF_CLASS ELFCLASS32
165847ae93cdSMichael Clark #else
165947ae93cdSMichael Clark #define ELF_CLASS ELFCLASS64
166047ae93cdSMichael Clark #endif
166147ae93cdSMichael Clark 
1662cb46938cSKito Cheng #define ELF_HWCAP get_elf_hwcap()
1663cb46938cSKito Cheng 
1664cb46938cSKito Cheng static uint32_t get_elf_hwcap(void)
1665cb46938cSKito Cheng {
1666cb46938cSKito Cheng #define MISA_BIT(EXT) (1 << (EXT - 'A'))
1667cb46938cSKito Cheng     RISCVCPU *cpu = RISCV_CPU(thread_cpu);
1668cb46938cSKito Cheng     uint32_t mask = MISA_BIT('I') | MISA_BIT('M') | MISA_BIT('A')
1669cb46938cSKito Cheng                     | MISA_BIT('F') | MISA_BIT('D') | MISA_BIT('C');
1670cb46938cSKito Cheng 
1671e91a7227SRichard Henderson     return cpu->env.misa_ext & mask;
1672cb46938cSKito Cheng #undef MISA_BIT
1673cb46938cSKito Cheng }
1674cb46938cSKito Cheng 
167547ae93cdSMichael Clark static inline void init_thread(struct target_pt_regs *regs,
167647ae93cdSMichael Clark                                struct image_info *infop)
167747ae93cdSMichael Clark {
167847ae93cdSMichael Clark     regs->sepc = infop->entry;
167947ae93cdSMichael Clark     regs->sp = infop->start_stack;
168047ae93cdSMichael Clark }
168147ae93cdSMichael Clark 
168247ae93cdSMichael Clark #define ELF_EXEC_PAGESIZE 4096
168347ae93cdSMichael Clark 
168447ae93cdSMichael Clark #endif /* TARGET_RISCV */
168547ae93cdSMichael Clark 
16867c248bcdSRichard Henderson #ifdef TARGET_HPPA
16877c248bcdSRichard Henderson 
16887c248bcdSRichard Henderson #define ELF_START_MMAP  0x80000000
16897c248bcdSRichard Henderson #define ELF_CLASS       ELFCLASS32
16907c248bcdSRichard Henderson #define ELF_ARCH        EM_PARISC
16917c248bcdSRichard Henderson #define ELF_PLATFORM    "PARISC"
16927c248bcdSRichard Henderson #define STACK_GROWS_DOWN 0
16937c248bcdSRichard Henderson #define STACK_ALIGNMENT  64
16947c248bcdSRichard Henderson 
16957c248bcdSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
16967c248bcdSRichard Henderson                                struct image_info *infop)
16977c248bcdSRichard Henderson {
16987c248bcdSRichard Henderson     regs->iaoq[0] = infop->entry;
16997c248bcdSRichard Henderson     regs->iaoq[1] = infop->entry + 4;
17007c248bcdSRichard Henderson     regs->gr[23] = 0;
170160f1c801SRichard Henderson     regs->gr[24] = infop->argv;
170260f1c801SRichard Henderson     regs->gr[25] = infop->argc;
17037c248bcdSRichard Henderson     /* The top-of-stack contains a linkage buffer.  */
17047c248bcdSRichard Henderson     regs->gr[30] = infop->start_stack + 64;
17057c248bcdSRichard Henderson     regs->gr[31] = infop->entry;
17067c248bcdSRichard Henderson }
17077c248bcdSRichard Henderson 
1708eee816c0SRichard Henderson #define LO_COMMPAGE  0
1709eee816c0SRichard Henderson 
1710eee816c0SRichard Henderson static bool init_guest_commpage(void)
1711eee816c0SRichard Henderson {
1712eee816c0SRichard Henderson     void *want = g2h_untagged(LO_COMMPAGE);
1713eee816c0SRichard Henderson     void *addr = mmap(want, qemu_host_page_size, PROT_NONE,
1714eee816c0SRichard Henderson                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1715eee816c0SRichard Henderson 
1716eee816c0SRichard Henderson     if (addr == MAP_FAILED) {
1717eee816c0SRichard Henderson         perror("Allocating guest commpage");
1718eee816c0SRichard Henderson         exit(EXIT_FAILURE);
1719eee816c0SRichard Henderson     }
1720eee816c0SRichard Henderson     if (addr != want) {
1721eee816c0SRichard Henderson         return false;
1722eee816c0SRichard Henderson     }
1723eee816c0SRichard Henderson 
1724eee816c0SRichard Henderson     /*
1725eee816c0SRichard Henderson      * On Linux, page zero is normally marked execute only + gateway.
1726eee816c0SRichard Henderson      * Normal read or write is supposed to fail (thus PROT_NONE above),
1727eee816c0SRichard Henderson      * but specific offsets have kernel code mapped to raise permissions
1728eee816c0SRichard Henderson      * and implement syscalls.  Here, simply mark the page executable.
1729eee816c0SRichard Henderson      * Special case the entry points during translation (see do_page_zero).
1730eee816c0SRichard Henderson      */
1731*49840a4aSRichard Henderson     page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
1732eee816c0SRichard Henderson                    PAGE_EXEC | PAGE_VALID);
1733eee816c0SRichard Henderson     return true;
1734eee816c0SRichard Henderson }
1735eee816c0SRichard Henderson 
17367c248bcdSRichard Henderson #endif /* TARGET_HPPA */
17377c248bcdSRichard Henderson 
1738ba7651fbSMax Filippov #ifdef TARGET_XTENSA
1739ba7651fbSMax Filippov 
1740ba7651fbSMax Filippov #define ELF_START_MMAP 0x20000000
1741ba7651fbSMax Filippov 
1742ba7651fbSMax Filippov #define ELF_CLASS       ELFCLASS32
1743ba7651fbSMax Filippov #define ELF_ARCH        EM_XTENSA
1744ba7651fbSMax Filippov 
1745ba7651fbSMax Filippov static inline void init_thread(struct target_pt_regs *regs,
1746ba7651fbSMax Filippov                                struct image_info *infop)
1747ba7651fbSMax Filippov {
1748ba7651fbSMax Filippov     regs->windowbase = 0;
1749ba7651fbSMax Filippov     regs->windowstart = 1;
1750ba7651fbSMax Filippov     regs->areg[1] = infop->start_stack;
1751ba7651fbSMax Filippov     regs->pc = infop->entry;
1752d2796be6SMax Filippov     if (info_is_fdpic(infop)) {
1753d2796be6SMax Filippov         regs->areg[4] = infop->loadmap_addr;
1754d2796be6SMax Filippov         regs->areg[5] = infop->interpreter_loadmap_addr;
1755d2796be6SMax Filippov         if (infop->interpreter_loadmap_addr) {
1756d2796be6SMax Filippov             regs->areg[6] = infop->interpreter_pt_dynamic_addr;
1757d2796be6SMax Filippov         } else {
1758d2796be6SMax Filippov             regs->areg[6] = infop->pt_dynamic_addr;
1759d2796be6SMax Filippov         }
1760d2796be6SMax Filippov     }
1761ba7651fbSMax Filippov }
1762ba7651fbSMax Filippov 
1763ba7651fbSMax Filippov /* See linux kernel: arch/xtensa/include/asm/elf.h.  */
1764ba7651fbSMax Filippov #define ELF_NREG 128
1765ba7651fbSMax Filippov typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1766ba7651fbSMax Filippov 
1767ba7651fbSMax Filippov enum {
1768ba7651fbSMax Filippov     TARGET_REG_PC,
1769ba7651fbSMax Filippov     TARGET_REG_PS,
1770ba7651fbSMax Filippov     TARGET_REG_LBEG,
1771ba7651fbSMax Filippov     TARGET_REG_LEND,
1772ba7651fbSMax Filippov     TARGET_REG_LCOUNT,
1773ba7651fbSMax Filippov     TARGET_REG_SAR,
1774ba7651fbSMax Filippov     TARGET_REG_WINDOWSTART,
1775ba7651fbSMax Filippov     TARGET_REG_WINDOWBASE,
1776ba7651fbSMax Filippov     TARGET_REG_THREADPTR,
1777ba7651fbSMax Filippov     TARGET_REG_AR0 = 64,
1778ba7651fbSMax Filippov };
1779ba7651fbSMax Filippov 
1780ba7651fbSMax Filippov static void elf_core_copy_regs(target_elf_gregset_t *regs,
1781ba7651fbSMax Filippov                                const CPUXtensaState *env)
1782ba7651fbSMax Filippov {
1783ba7651fbSMax Filippov     unsigned i;
1784ba7651fbSMax Filippov 
1785ba7651fbSMax Filippov     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
1786ba7651fbSMax Filippov     (*regs)[TARGET_REG_PS] = tswapreg(env->sregs[PS] & ~PS_EXCM);
1787ba7651fbSMax Filippov     (*regs)[TARGET_REG_LBEG] = tswapreg(env->sregs[LBEG]);
1788ba7651fbSMax Filippov     (*regs)[TARGET_REG_LEND] = tswapreg(env->sregs[LEND]);
1789ba7651fbSMax Filippov     (*regs)[TARGET_REG_LCOUNT] = tswapreg(env->sregs[LCOUNT]);
1790ba7651fbSMax Filippov     (*regs)[TARGET_REG_SAR] = tswapreg(env->sregs[SAR]);
1791ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWSTART] = tswapreg(env->sregs[WINDOW_START]);
1792ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWBASE] = tswapreg(env->sregs[WINDOW_BASE]);
1793ba7651fbSMax Filippov     (*regs)[TARGET_REG_THREADPTR] = tswapreg(env->uregs[THREADPTR]);
1794ba7651fbSMax Filippov     xtensa_sync_phys_from_window((CPUXtensaState *)env);
1795ba7651fbSMax Filippov     for (i = 0; i < env->config->nareg; ++i) {
1796ba7651fbSMax Filippov         (*regs)[TARGET_REG_AR0 + i] = tswapreg(env->phys_regs[i]);
1797ba7651fbSMax Filippov     }
1798ba7651fbSMax Filippov }
1799ba7651fbSMax Filippov 
1800ba7651fbSMax Filippov #define USE_ELF_CORE_DUMP
1801ba7651fbSMax Filippov #define ELF_EXEC_PAGESIZE       4096
1802ba7651fbSMax Filippov 
1803ba7651fbSMax Filippov #endif /* TARGET_XTENSA */
1804ba7651fbSMax Filippov 
1805d2a56bd2STaylor Simpson #ifdef TARGET_HEXAGON
1806d2a56bd2STaylor Simpson 
1807d2a56bd2STaylor Simpson #define ELF_START_MMAP 0x20000000
1808d2a56bd2STaylor Simpson 
1809d2a56bd2STaylor Simpson #define ELF_CLASS       ELFCLASS32
1810d2a56bd2STaylor Simpson #define ELF_ARCH        EM_HEXAGON
1811d2a56bd2STaylor Simpson 
1812d2a56bd2STaylor Simpson static inline void init_thread(struct target_pt_regs *regs,
1813d2a56bd2STaylor Simpson                                struct image_info *infop)
1814d2a56bd2STaylor Simpson {
1815d2a56bd2STaylor Simpson     regs->sepc = infop->entry;
1816d2a56bd2STaylor Simpson     regs->sp = infop->start_stack;
1817d2a56bd2STaylor Simpson }
1818d2a56bd2STaylor Simpson 
1819d2a56bd2STaylor Simpson #endif /* TARGET_HEXAGON */
1820d2a56bd2STaylor Simpson 
1821fcdc0ab4SJiaxun Yang #ifndef ELF_BASE_PLATFORM
1822fcdc0ab4SJiaxun Yang #define ELF_BASE_PLATFORM (NULL)
1823fcdc0ab4SJiaxun Yang #endif
1824fcdc0ab4SJiaxun Yang 
182515338fd7Sbellard #ifndef ELF_PLATFORM
182615338fd7Sbellard #define ELF_PLATFORM (NULL)
182715338fd7Sbellard #endif
182815338fd7Sbellard 
182975be901cSPeter Crosthwaite #ifndef ELF_MACHINE
183075be901cSPeter Crosthwaite #define ELF_MACHINE ELF_ARCH
183175be901cSPeter Crosthwaite #endif
183275be901cSPeter Crosthwaite 
1833d276a604SPeter Crosthwaite #ifndef elf_check_arch
1834d276a604SPeter Crosthwaite #define elf_check_arch(x) ((x) == ELF_ARCH)
1835d276a604SPeter Crosthwaite #endif
1836d276a604SPeter Crosthwaite 
1837ace3d654SCarlo Marcelo Arenas Belón #ifndef elf_check_abi
1838ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (1)
1839ace3d654SCarlo Marcelo Arenas Belón #endif
1840ace3d654SCarlo Marcelo Arenas Belón 
184115338fd7Sbellard #ifndef ELF_HWCAP
184215338fd7Sbellard #define ELF_HWCAP 0
184315338fd7Sbellard #endif
184415338fd7Sbellard 
18457c4ee5bcSRichard Henderson #ifndef STACK_GROWS_DOWN
18467c4ee5bcSRichard Henderson #define STACK_GROWS_DOWN 1
18477c4ee5bcSRichard Henderson #endif
18487c4ee5bcSRichard Henderson 
18497c4ee5bcSRichard Henderson #ifndef STACK_ALIGNMENT
18507c4ee5bcSRichard Henderson #define STACK_ALIGNMENT 16
18517c4ee5bcSRichard Henderson #endif
18527c4ee5bcSRichard Henderson 
1853992f48a0Sblueswir1 #ifdef TARGET_ABI32
1854cb33da57Sblueswir1 #undef ELF_CLASS
1855992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
1856cb33da57Sblueswir1 #undef bswaptls
1857cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
1858cb33da57Sblueswir1 #endif
1859cb33da57Sblueswir1 
1860872f3d04SRichard Henderson #ifndef EXSTACK_DEFAULT
1861872f3d04SRichard Henderson #define EXSTACK_DEFAULT false
1862872f3d04SRichard Henderson #endif
1863872f3d04SRichard Henderson 
186431e31b8aSbellard #include "elf.h"
186509bfb054Sbellard 
1866e8384b37SRichard Henderson /* We must delay the following stanzas until after "elf.h". */
1867e8384b37SRichard Henderson #if defined(TARGET_AARCH64)
1868e8384b37SRichard Henderson 
1869e8384b37SRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
1870e8384b37SRichard Henderson                                     const uint32_t *data,
1871e8384b37SRichard Henderson                                     struct image_info *info,
1872e8384b37SRichard Henderson                                     Error **errp)
1873e8384b37SRichard Henderson {
1874e8384b37SRichard Henderson     if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
1875e8384b37SRichard Henderson         if (pr_datasz != sizeof(uint32_t)) {
1876e8384b37SRichard Henderson             error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
1877e8384b37SRichard Henderson             return false;
1878e8384b37SRichard Henderson         }
1879e8384b37SRichard Henderson         /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
1880e8384b37SRichard Henderson         info->note_flags = *data;
1881e8384b37SRichard Henderson     }
1882e8384b37SRichard Henderson     return true;
1883e8384b37SRichard Henderson }
1884e8384b37SRichard Henderson #define ARCH_USE_GNU_PROPERTY 1
1885e8384b37SRichard Henderson 
1886e8384b37SRichard Henderson #else
1887e8384b37SRichard Henderson 
188883f990ebSRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
188983f990ebSRichard Henderson                                     const uint32_t *data,
189083f990ebSRichard Henderson                                     struct image_info *info,
189183f990ebSRichard Henderson                                     Error **errp)
189283f990ebSRichard Henderson {
189383f990ebSRichard Henderson     g_assert_not_reached();
189483f990ebSRichard Henderson }
189583f990ebSRichard Henderson #define ARCH_USE_GNU_PROPERTY 0
189683f990ebSRichard Henderson 
1897e8384b37SRichard Henderson #endif
1898e8384b37SRichard Henderson 
189909bfb054Sbellard struct exec
190009bfb054Sbellard {
190109bfb054Sbellard     unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
190209bfb054Sbellard     unsigned int a_text;   /* length of text, in bytes */
190309bfb054Sbellard     unsigned int a_data;   /* length of data, in bytes */
190409bfb054Sbellard     unsigned int a_bss;    /* length of uninitialized data area, in bytes */
190509bfb054Sbellard     unsigned int a_syms;   /* length of symbol table data in file, in bytes */
190609bfb054Sbellard     unsigned int a_entry;  /* start address */
190709bfb054Sbellard     unsigned int a_trsize; /* length of relocation info for text, in bytes */
190809bfb054Sbellard     unsigned int a_drsize; /* length of relocation info for data, in bytes */
190909bfb054Sbellard };
191009bfb054Sbellard 
191109bfb054Sbellard 
191209bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
191309bfb054Sbellard #define OMAGIC 0407
191409bfb054Sbellard #define NMAGIC 0410
191509bfb054Sbellard #define ZMAGIC 0413
191609bfb054Sbellard #define QMAGIC 0314
191709bfb054Sbellard 
191831e31b8aSbellard /* Necessary parameters */
191994894ff2SShivaprasad G Bhat #define TARGET_ELF_EXEC_PAGESIZE \
192094894ff2SShivaprasad G Bhat         (((eppnt->p_align & ~qemu_host_page_mask) != 0) ? \
192194894ff2SShivaprasad G Bhat          TARGET_PAGE_SIZE : MAX(qemu_host_page_size, TARGET_PAGE_SIZE))
192294894ff2SShivaprasad G Bhat #define TARGET_ELF_PAGELENGTH(_v) ROUND_UP((_v), TARGET_ELF_EXEC_PAGESIZE)
192379cb1f1dSYongbok Kim #define TARGET_ELF_PAGESTART(_v) ((_v) & \
192479cb1f1dSYongbok Kim                                  ~(abi_ulong)(TARGET_ELF_EXEC_PAGESIZE-1))
192554936004Sbellard #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
192631e31b8aSbellard 
1927e0d1673dSLirong Yuan #define DLINFO_ITEMS 16
192831e31b8aSbellard 
192909bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
193009bfb054Sbellard {
193109bfb054Sbellard     memcpy(to, from, n);
193209bfb054Sbellard }
193309bfb054Sbellard 
193431e31b8aSbellard #ifdef BSWAP_NEEDED
193592a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
193631e31b8aSbellard {
193731e31b8aSbellard     bswap16s(&ehdr->e_type);            /* Object file type */
193831e31b8aSbellard     bswap16s(&ehdr->e_machine);         /* Architecture */
193931e31b8aSbellard     bswap32s(&ehdr->e_version);         /* Object file version */
194092a31b1fSbellard     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
194192a31b1fSbellard     bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
194292a31b1fSbellard     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
194331e31b8aSbellard     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
194431e31b8aSbellard     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
194531e31b8aSbellard     bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
194631e31b8aSbellard     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
194731e31b8aSbellard     bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
194831e31b8aSbellard     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
194931e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
195031e31b8aSbellard }
195131e31b8aSbellard 
1952991f8f0cSRichard Henderson static void bswap_phdr(struct elf_phdr *phdr, int phnum)
195331e31b8aSbellard {
1954991f8f0cSRichard Henderson     int i;
1955991f8f0cSRichard Henderson     for (i = 0; i < phnum; ++i, ++phdr) {
195631e31b8aSbellard         bswap32s(&phdr->p_type);        /* Segment type */
1957991f8f0cSRichard Henderson         bswap32s(&phdr->p_flags);       /* Segment flags */
195892a31b1fSbellard         bswaptls(&phdr->p_offset);      /* Segment file offset */
195992a31b1fSbellard         bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
196092a31b1fSbellard         bswaptls(&phdr->p_paddr);       /* Segment physical address */
196192a31b1fSbellard         bswaptls(&phdr->p_filesz);      /* Segment size in file */
196292a31b1fSbellard         bswaptls(&phdr->p_memsz);       /* Segment size in memory */
196392a31b1fSbellard         bswaptls(&phdr->p_align);       /* Segment alignment */
196431e31b8aSbellard     }
1965991f8f0cSRichard Henderson }
1966689f936fSbellard 
1967991f8f0cSRichard Henderson static void bswap_shdr(struct elf_shdr *shdr, int shnum)
1968689f936fSbellard {
1969991f8f0cSRichard Henderson     int i;
1970991f8f0cSRichard Henderson     for (i = 0; i < shnum; ++i, ++shdr) {
1971689f936fSbellard         bswap32s(&shdr->sh_name);
1972689f936fSbellard         bswap32s(&shdr->sh_type);
197392a31b1fSbellard         bswaptls(&shdr->sh_flags);
197492a31b1fSbellard         bswaptls(&shdr->sh_addr);
197592a31b1fSbellard         bswaptls(&shdr->sh_offset);
197692a31b1fSbellard         bswaptls(&shdr->sh_size);
1977689f936fSbellard         bswap32s(&shdr->sh_link);
1978689f936fSbellard         bswap32s(&shdr->sh_info);
197992a31b1fSbellard         bswaptls(&shdr->sh_addralign);
198092a31b1fSbellard         bswaptls(&shdr->sh_entsize);
1981689f936fSbellard     }
1982991f8f0cSRichard Henderson }
1983689f936fSbellard 
19847a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
1985689f936fSbellard {
1986689f936fSbellard     bswap32s(&sym->st_name);
19877a3148a9Sj_mayer     bswaptls(&sym->st_value);
19887a3148a9Sj_mayer     bswaptls(&sym->st_size);
1989689f936fSbellard     bswap16s(&sym->st_shndx);
1990689f936fSbellard }
19915dd0db52SStefan Markovic 
19925dd0db52SStefan Markovic #ifdef TARGET_MIPS
19935dd0db52SStefan Markovic static void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags)
19945dd0db52SStefan Markovic {
19955dd0db52SStefan Markovic     bswap16s(&abiflags->version);
19965dd0db52SStefan Markovic     bswap32s(&abiflags->ases);
19975dd0db52SStefan Markovic     bswap32s(&abiflags->isa_ext);
19985dd0db52SStefan Markovic     bswap32s(&abiflags->flags1);
19995dd0db52SStefan Markovic     bswap32s(&abiflags->flags2);
20005dd0db52SStefan Markovic }
20015dd0db52SStefan Markovic #endif
2002991f8f0cSRichard Henderson #else
2003991f8f0cSRichard Henderson static inline void bswap_ehdr(struct elfhdr *ehdr) { }
2004991f8f0cSRichard Henderson static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
2005991f8f0cSRichard Henderson static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
2006991f8f0cSRichard Henderson static inline void bswap_sym(struct elf_sym *sym) { }
20075dd0db52SStefan Markovic #ifdef TARGET_MIPS
20085dd0db52SStefan Markovic static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { }
20095dd0db52SStefan Markovic #endif
201031e31b8aSbellard #endif
201131e31b8aSbellard 
2012edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
20139349b4f9SAndreas Färber static int elf_core_dump(int, const CPUArchState *);
2014edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
2015682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
2016edf8e2afSMika Westerberg 
20179058abddSRichard Henderson /* Verify the portions of EHDR within E_IDENT for the target.
20189058abddSRichard Henderson    This can be performed before bswapping the entire header.  */
20199058abddSRichard Henderson static bool elf_check_ident(struct elfhdr *ehdr)
20209058abddSRichard Henderson {
20219058abddSRichard Henderson     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
20229058abddSRichard Henderson             && ehdr->e_ident[EI_MAG1] == ELFMAG1
20239058abddSRichard Henderson             && ehdr->e_ident[EI_MAG2] == ELFMAG2
20249058abddSRichard Henderson             && ehdr->e_ident[EI_MAG3] == ELFMAG3
20259058abddSRichard Henderson             && ehdr->e_ident[EI_CLASS] == ELF_CLASS
20269058abddSRichard Henderson             && ehdr->e_ident[EI_DATA] == ELF_DATA
20279058abddSRichard Henderson             && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
20289058abddSRichard Henderson }
20299058abddSRichard Henderson 
20309058abddSRichard Henderson /* Verify the portions of EHDR outside of E_IDENT for the target.
20319058abddSRichard Henderson    This has to wait until after bswapping the header.  */
20329058abddSRichard Henderson static bool elf_check_ehdr(struct elfhdr *ehdr)
20339058abddSRichard Henderson {
20349058abddSRichard Henderson     return (elf_check_arch(ehdr->e_machine)
2035ace3d654SCarlo Marcelo Arenas Belón             && elf_check_abi(ehdr->e_flags)
20369058abddSRichard Henderson             && ehdr->e_ehsize == sizeof(struct elfhdr)
20379058abddSRichard Henderson             && ehdr->e_phentsize == sizeof(struct elf_phdr)
20389058abddSRichard Henderson             && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
20399058abddSRichard Henderson }
20409058abddSRichard Henderson 
204131e31b8aSbellard /*
2042e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
204331e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
204431e31b8aSbellard  * to be put directly into the top of new user memory.
204531e31b8aSbellard  *
204631e31b8aSbellard  */
204759baae9aSStefan Brüns static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch,
204859baae9aSStefan Brüns                                   abi_ulong p, abi_ulong stack_limit)
204931e31b8aSbellard {
205059baae9aSStefan Brüns     char *tmp;
20517c4ee5bcSRichard Henderson     int len, i;
205259baae9aSStefan Brüns     abi_ulong top = p;
205331e31b8aSbellard 
205431e31b8aSbellard     if (!p) {
205531e31b8aSbellard         return 0;       /* bullet-proofing */
205631e31b8aSbellard     }
205759baae9aSStefan Brüns 
20587c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
20597c4ee5bcSRichard Henderson         int offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
20607c4ee5bcSRichard Henderson         for (i = argc - 1; i >= 0; --i) {
20617c4ee5bcSRichard Henderson             tmp = argv[i];
2062edf779ffSbellard             if (!tmp) {
206331e31b8aSbellard                 fprintf(stderr, "VFS: argc is wrong");
206431e31b8aSbellard                 exit(-1);
206531e31b8aSbellard             }
206659baae9aSStefan Brüns             len = strlen(tmp) + 1;
206759baae9aSStefan Brüns             tmp += len;
206859baae9aSStefan Brüns 
206959baae9aSStefan Brüns             if (len > (p - stack_limit)) {
207031e31b8aSbellard                 return 0;
207131e31b8aSbellard             }
207231e31b8aSbellard             while (len) {
207331e31b8aSbellard                 int bytes_to_copy = (len > offset) ? offset : len;
207431e31b8aSbellard                 tmp -= bytes_to_copy;
207531e31b8aSbellard                 p -= bytes_to_copy;
207631e31b8aSbellard                 offset -= bytes_to_copy;
207731e31b8aSbellard                 len -= bytes_to_copy;
207859baae9aSStefan Brüns 
207959baae9aSStefan Brüns                 memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
208059baae9aSStefan Brüns 
208159baae9aSStefan Brüns                 if (offset == 0) {
208259baae9aSStefan Brüns                     memcpy_to_target(p, scratch, top - p);
208359baae9aSStefan Brüns                     top = p;
208459baae9aSStefan Brüns                     offset = TARGET_PAGE_SIZE;
208531e31b8aSbellard                 }
208631e31b8aSbellard             }
208731e31b8aSbellard         }
20887c4ee5bcSRichard Henderson         if (p != top) {
208959baae9aSStefan Brüns             memcpy_to_target(p, scratch + offset, top - p);
209059baae9aSStefan Brüns         }
20917c4ee5bcSRichard Henderson     } else {
20927c4ee5bcSRichard Henderson         int remaining = TARGET_PAGE_SIZE - (p % TARGET_PAGE_SIZE);
20937c4ee5bcSRichard Henderson         for (i = 0; i < argc; ++i) {
20947c4ee5bcSRichard Henderson             tmp = argv[i];
20957c4ee5bcSRichard Henderson             if (!tmp) {
20967c4ee5bcSRichard Henderson                 fprintf(stderr, "VFS: argc is wrong");
20977c4ee5bcSRichard Henderson                 exit(-1);
20987c4ee5bcSRichard Henderson             }
20997c4ee5bcSRichard Henderson             len = strlen(tmp) + 1;
21007c4ee5bcSRichard Henderson             if (len > (stack_limit - p)) {
21017c4ee5bcSRichard Henderson                 return 0;
21027c4ee5bcSRichard Henderson             }
21037c4ee5bcSRichard Henderson             while (len) {
21047c4ee5bcSRichard Henderson                 int bytes_to_copy = (len > remaining) ? remaining : len;
21057c4ee5bcSRichard Henderson 
21067c4ee5bcSRichard Henderson                 memcpy_fromfs(scratch + (p - top), tmp, bytes_to_copy);
21077c4ee5bcSRichard Henderson 
21087c4ee5bcSRichard Henderson                 tmp += bytes_to_copy;
21097c4ee5bcSRichard Henderson                 remaining -= bytes_to_copy;
21107c4ee5bcSRichard Henderson                 p += bytes_to_copy;
21117c4ee5bcSRichard Henderson                 len -= bytes_to_copy;
21127c4ee5bcSRichard Henderson 
21137c4ee5bcSRichard Henderson                 if (remaining == 0) {
21147c4ee5bcSRichard Henderson                     memcpy_to_target(top, scratch, p - top);
21157c4ee5bcSRichard Henderson                     top = p;
21167c4ee5bcSRichard Henderson                     remaining = TARGET_PAGE_SIZE;
21177c4ee5bcSRichard Henderson                 }
21187c4ee5bcSRichard Henderson             }
21197c4ee5bcSRichard Henderson         }
21207c4ee5bcSRichard Henderson         if (p != top) {
21217c4ee5bcSRichard Henderson             memcpy_to_target(top, scratch, p - top);
21227c4ee5bcSRichard Henderson         }
21237c4ee5bcSRichard Henderson     }
212459baae9aSStefan Brüns 
212531e31b8aSbellard     return p;
212631e31b8aSbellard }
212731e31b8aSbellard 
212859baae9aSStefan Brüns /* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of
212959baae9aSStefan Brüns  * argument/environment space. Newer kernels (>2.6.33) allow more,
213059baae9aSStefan Brüns  * dependent on stack size, but guarantee at least 32 pages for
213159baae9aSStefan Brüns  * backwards compatibility.
213259baae9aSStefan Brüns  */
213359baae9aSStefan Brüns #define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE)
213459baae9aSStefan Brüns 
213559baae9aSStefan Brüns static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
213631e31b8aSbellard                                  struct image_info *info)
213731e31b8aSbellard {
213859baae9aSStefan Brüns     abi_ulong size, error, guard;
2139872f3d04SRichard Henderson     int prot;
214031e31b8aSbellard 
2141703e0e89SRichard Henderson     size = guest_stack_size;
214259baae9aSStefan Brüns     if (size < STACK_LOWER_LIMIT) {
214359baae9aSStefan Brüns         size = STACK_LOWER_LIMIT;
214460dcbcb5SRichard Henderson     }
2145f4388205SHelge Deller 
2146f4388205SHelge Deller     if (STACK_GROWS_DOWN) {
214760dcbcb5SRichard Henderson         guard = TARGET_PAGE_SIZE;
21488e3b0cbbSMarc-André Lureau         if (guard < qemu_real_host_page_size()) {
21498e3b0cbbSMarc-André Lureau             guard = qemu_real_host_page_size();
215060dcbcb5SRichard Henderson         }
2151f4388205SHelge Deller     } else {
2152f4388205SHelge Deller         /* no guard page for hppa target where stack grows upwards. */
2153f4388205SHelge Deller         guard = 0;
2154f4388205SHelge Deller     }
215560dcbcb5SRichard Henderson 
2156872f3d04SRichard Henderson     prot = PROT_READ | PROT_WRITE;
2157872f3d04SRichard Henderson     if (info->exec_stack) {
2158872f3d04SRichard Henderson         prot |= PROT_EXEC;
2159872f3d04SRichard Henderson     }
2160872f3d04SRichard Henderson     error = target_mmap(0, size + guard, prot,
216160dcbcb5SRichard Henderson                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
216209bfb054Sbellard     if (error == -1) {
216360dcbcb5SRichard Henderson         perror("mmap stack");
216431e31b8aSbellard         exit(-1);
216531e31b8aSbellard     }
216631e31b8aSbellard 
216760dcbcb5SRichard Henderson     /* We reserve one extra page at the top of the stack as guard.  */
21687c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
216960dcbcb5SRichard Henderson         target_mprotect(error, guard, PROT_NONE);
217060dcbcb5SRichard Henderson         info->stack_limit = error + guard;
217159baae9aSStefan Brüns         return info->stack_limit + size - sizeof(void *);
21727c4ee5bcSRichard Henderson     } else {
21737c4ee5bcSRichard Henderson         info->stack_limit = error + size;
21747c4ee5bcSRichard Henderson         return error;
21757c4ee5bcSRichard Henderson     }
217631e31b8aSbellard }
217731e31b8aSbellard 
2178cf129f3aSRichard Henderson /* Map and zero the bss.  We need to explicitly zero any fractional pages
2179cf129f3aSRichard Henderson    after the data section (i.e. bss).  */
2180cf129f3aSRichard Henderson static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
218131e31b8aSbellard {
2182cf129f3aSRichard Henderson     uintptr_t host_start, host_map_start, host_end;
2183cf129f3aSRichard Henderson 
2184cf129f3aSRichard Henderson     last_bss = TARGET_PAGE_ALIGN(last_bss);
2185cf129f3aSRichard Henderson 
2186cf129f3aSRichard Henderson     /* ??? There is confusion between qemu_real_host_page_size and
2187cf129f3aSRichard Henderson        qemu_host_page_size here and elsewhere in target_mmap, which
2188cf129f3aSRichard Henderson        may lead to the end of the data section mapping from the file
2189cf129f3aSRichard Henderson        not being mapped.  At least there was an explicit test and
2190cf129f3aSRichard Henderson        comment for that here, suggesting that "the file size must
2191cf129f3aSRichard Henderson        be known".  The comment probably pre-dates the introduction
2192cf129f3aSRichard Henderson        of the fstat system call in target_mmap which does in fact
2193cf129f3aSRichard Henderson        find out the size.  What isn't clear is if the workaround
2194cf129f3aSRichard Henderson        here is still actually needed.  For now, continue with it,
2195cf129f3aSRichard Henderson        but merge it with the "normal" mmap that would allocate the bss.  */
2196cf129f3aSRichard Henderson 
21973e8f1628SRichard Henderson     host_start = (uintptr_t) g2h_untagged(elf_bss);
21983e8f1628SRichard Henderson     host_end = (uintptr_t) g2h_untagged(last_bss);
21990c2d70c4SPaolo Bonzini     host_map_start = REAL_HOST_PAGE_ALIGN(host_start);
2200cf129f3aSRichard Henderson 
2201cf129f3aSRichard Henderson     if (host_map_start < host_end) {
2202cf129f3aSRichard Henderson         void *p = mmap((void *)host_map_start, host_end - host_map_start,
2203cf129f3aSRichard Henderson                        prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
2204cf129f3aSRichard Henderson         if (p == MAP_FAILED) {
220531e31b8aSbellard             perror("cannot mmap brk");
220631e31b8aSbellard             exit(-1);
220731e31b8aSbellard         }
2208f46e9a0bSTom Musta     }
2209cf129f3aSRichard Henderson 
2210f46e9a0bSTom Musta     /* Ensure that the bss page(s) are valid */
2211f46e9a0bSTom Musta     if ((page_get_flags(last_bss-1) & prot) != prot) {
2212*49840a4aSRichard Henderson         page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss - 1,
2213*49840a4aSRichard Henderson                        prot | PAGE_VALID);
221431e31b8aSbellard     }
221531e31b8aSbellard 
2216cf129f3aSRichard Henderson     if (host_start < host_map_start) {
2217cf129f3aSRichard Henderson         memset((void *)host_start, 0, host_map_start - host_start);
2218853d6f7aSbellard     }
2219853d6f7aSbellard }
2220853d6f7aSbellard 
2221d2796be6SMax Filippov #if defined(TARGET_ARM)
2222cf58affeSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2223cf58affeSChristophe Lyon {
2224cf58affeSChristophe Lyon     return exec->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC;
2225cf58affeSChristophe Lyon }
2226d2796be6SMax Filippov #elif defined(TARGET_XTENSA)
2227d2796be6SMax Filippov static int elf_is_fdpic(struct elfhdr *exec)
2228d2796be6SMax Filippov {
2229d2796be6SMax Filippov     return exec->e_ident[EI_OSABI] == ELFOSABI_XTENSA_FDPIC;
2230d2796be6SMax Filippov }
2231cf58affeSChristophe Lyon #else
2232a99856cdSChristophe Lyon /* Default implementation, always false.  */
2233a99856cdSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2234a99856cdSChristophe Lyon {
2235a99856cdSChristophe Lyon     return 0;
2236a99856cdSChristophe Lyon }
2237cf58affeSChristophe Lyon #endif
2238a99856cdSChristophe Lyon 
22391af02e83SMike Frysinger static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
22401af02e83SMike Frysinger {
22411af02e83SMike Frysinger     uint16_t n;
22421af02e83SMike Frysinger     struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
22431af02e83SMike Frysinger 
22441af02e83SMike Frysinger     /* elf32_fdpic_loadseg */
22451af02e83SMike Frysinger     n = info->nsegs;
22461af02e83SMike Frysinger     while (n--) {
22471af02e83SMike Frysinger         sp -= 12;
22481af02e83SMike Frysinger         put_user_u32(loadsegs[n].addr, sp+0);
22491af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_vaddr, sp+4);
22501af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_memsz, sp+8);
22511af02e83SMike Frysinger     }
22521af02e83SMike Frysinger 
22531af02e83SMike Frysinger     /* elf32_fdpic_loadmap */
22541af02e83SMike Frysinger     sp -= 4;
22551af02e83SMike Frysinger     put_user_u16(0, sp+0); /* version */
22561af02e83SMike Frysinger     put_user_u16(info->nsegs, sp+2); /* nsegs */
22571af02e83SMike Frysinger 
22581af02e83SMike Frysinger     info->personality = PER_LINUX_FDPIC;
22591af02e83SMike Frysinger     info->loadmap_addr = sp;
22601af02e83SMike Frysinger 
22611af02e83SMike Frysinger     return sp;
22621af02e83SMike Frysinger }
22631af02e83SMike Frysinger 
2264992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
226531e31b8aSbellard                                    struct elfhdr *exec,
22668e62a717SRichard Henderson                                    struct image_info *info,
22678e62a717SRichard Henderson                                    struct image_info *interp_info)
226831e31b8aSbellard {
2269992f48a0Sblueswir1     abi_ulong sp;
22707c4ee5bcSRichard Henderson     abi_ulong u_argc, u_argv, u_envp, u_auxv;
227153a5960aSpbrook     int size;
227214322badSLaurent ALFONSI     int i;
227314322badSLaurent ALFONSI     abi_ulong u_rand_bytes;
227414322badSLaurent ALFONSI     uint8_t k_rand_bytes[16];
2275fcdc0ab4SJiaxun Yang     abi_ulong u_platform, u_base_platform;
2276fcdc0ab4SJiaxun Yang     const char *k_platform, *k_base_platform;
2277863cf0b7Sj_mayer     const int n = sizeof(elf_addr_t);
227831e31b8aSbellard 
227953a5960aSpbrook     sp = p;
22801af02e83SMike Frysinger 
22811af02e83SMike Frysinger     /* Needs to be before we load the env/argc/... */
22821af02e83SMike Frysinger     if (elf_is_fdpic(exec)) {
22831af02e83SMike Frysinger         /* Need 4 byte alignment for these structs */
22841af02e83SMike Frysinger         sp &= ~3;
22851af02e83SMike Frysinger         sp = loader_build_fdpic_loadmap(info, sp);
22861af02e83SMike Frysinger         info->other_info = interp_info;
22871af02e83SMike Frysinger         if (interp_info) {
22881af02e83SMike Frysinger             interp_info->other_info = info;
22891af02e83SMike Frysinger             sp = loader_build_fdpic_loadmap(interp_info, sp);
22903cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = interp_info->loadmap_addr;
22913cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = interp_info->pt_dynamic_addr;
22923cb10cfaSChristophe Lyon         } else {
22933cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = 0;
22943cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = 0;
22951af02e83SMike Frysinger         }
22961af02e83SMike Frysinger     }
22971af02e83SMike Frysinger 
2298fcdc0ab4SJiaxun Yang     u_base_platform = 0;
2299fcdc0ab4SJiaxun Yang     k_base_platform = ELF_BASE_PLATFORM;
2300fcdc0ab4SJiaxun Yang     if (k_base_platform) {
2301fcdc0ab4SJiaxun Yang         size_t len = strlen(k_base_platform) + 1;
2302fcdc0ab4SJiaxun Yang         if (STACK_GROWS_DOWN) {
2303fcdc0ab4SJiaxun Yang             sp -= (len + n - 1) & ~(n - 1);
2304fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2305fcdc0ab4SJiaxun Yang             /* FIXME - check return value of memcpy_to_target() for failure */
2306fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2307fcdc0ab4SJiaxun Yang         } else {
2308fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2309fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2310fcdc0ab4SJiaxun Yang             sp += len + 1;
2311fcdc0ab4SJiaxun Yang         }
2312fcdc0ab4SJiaxun Yang     }
2313fcdc0ab4SJiaxun Yang 
231453a5960aSpbrook     u_platform = 0;
231515338fd7Sbellard     k_platform = ELF_PLATFORM;
231615338fd7Sbellard     if (k_platform) {
231715338fd7Sbellard         size_t len = strlen(k_platform) + 1;
23187c4ee5bcSRichard Henderson         if (STACK_GROWS_DOWN) {
231953a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
232053a5960aSpbrook             u_platform = sp;
2321579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
232253a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
23237c4ee5bcSRichard Henderson         } else {
23247c4ee5bcSRichard Henderson             memcpy_to_target(sp, k_platform, len);
23257c4ee5bcSRichard Henderson             u_platform = sp;
23267c4ee5bcSRichard Henderson             sp += len + 1;
23277c4ee5bcSRichard Henderson         }
23287c4ee5bcSRichard Henderson     }
23297c4ee5bcSRichard Henderson 
23307c4ee5bcSRichard Henderson     /* Provide 16 byte alignment for the PRNG, and basic alignment for
23317c4ee5bcSRichard Henderson      * the argv and envp pointers.
23327c4ee5bcSRichard Henderson      */
23337c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
23347c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_DOWN(sp, 16);
23357c4ee5bcSRichard Henderson     } else {
23367c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp, 16);
233715338fd7Sbellard     }
233814322badSLaurent ALFONSI 
233914322badSLaurent ALFONSI     /*
2340c6a2377fSRichard Henderson      * Generate 16 random bytes for userspace PRNG seeding.
234114322badSLaurent ALFONSI      */
2342c6a2377fSRichard Henderson     qemu_guest_getrandom_nofail(k_rand_bytes, sizeof(k_rand_bytes));
23437c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
234414322badSLaurent ALFONSI         sp -= 16;
234514322badSLaurent ALFONSI         u_rand_bytes = sp;
234614322badSLaurent ALFONSI         /* FIXME - check return value of memcpy_to_target() for failure */
234714322badSLaurent ALFONSI         memcpy_to_target(sp, k_rand_bytes, 16);
23487c4ee5bcSRichard Henderson     } else {
23497c4ee5bcSRichard Henderson         memcpy_to_target(sp, k_rand_bytes, 16);
23507c4ee5bcSRichard Henderson         u_rand_bytes = sp;
23517c4ee5bcSRichard Henderson         sp += 16;
23527c4ee5bcSRichard Henderson     }
235314322badSLaurent ALFONSI 
235453a5960aSpbrook     size = (DLINFO_ITEMS + 1) * 2;
2355fcdc0ab4SJiaxun Yang     if (k_base_platform)
2356fcdc0ab4SJiaxun Yang         size += 2;
235715338fd7Sbellard     if (k_platform)
235853a5960aSpbrook         size += 2;
2359f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
236053a5960aSpbrook     size += DLINFO_ARCH_ITEMS * 2;
2361f5155289Sbellard #endif
2362ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2363ad6919dcSPeter Maydell     size += 2;
2364ad6919dcSPeter Maydell #endif
2365f516511eSPeter Maydell     info->auxv_len = size * n;
2366f516511eSPeter Maydell 
236753a5960aSpbrook     size += envc + argc + 2;
2368b9329d4bSRichard Henderson     size += 1;  /* argc itself */
236953a5960aSpbrook     size *= n;
23707c4ee5bcSRichard Henderson 
23717c4ee5bcSRichard Henderson     /* Allocate space and finalize stack alignment for entry now.  */
23727c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
23737c4ee5bcSRichard Henderson         u_argc = QEMU_ALIGN_DOWN(sp - size, STACK_ALIGNMENT);
23747c4ee5bcSRichard Henderson         sp = u_argc;
23757c4ee5bcSRichard Henderson     } else {
23767c4ee5bcSRichard Henderson         u_argc = sp;
23777c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp + size, STACK_ALIGNMENT);
23787c4ee5bcSRichard Henderson     }
23797c4ee5bcSRichard Henderson 
23807c4ee5bcSRichard Henderson     u_argv = u_argc + n;
23817c4ee5bcSRichard Henderson     u_envp = u_argv + (argc + 1) * n;
23827c4ee5bcSRichard Henderson     u_auxv = u_envp + (envc + 1) * n;
23837c4ee5bcSRichard Henderson     info->saved_auxv = u_auxv;
238460f1c801SRichard Henderson     info->argc = argc;
238560f1c801SRichard Henderson     info->envc = envc;
238660f1c801SRichard Henderson     info->argv = u_argv;
238760f1c801SRichard Henderson     info->envp = u_envp;
2388f5155289Sbellard 
2389863cf0b7Sj_mayer     /* This is correct because Linux defines
2390863cf0b7Sj_mayer      * elf_addr_t as Elf32_Off / Elf64_Off
2391863cf0b7Sj_mayer      */
239253a5960aSpbrook #define NEW_AUX_ENT(id, val) do {               \
23937c4ee5bcSRichard Henderson         put_user_ual(id, u_auxv);  u_auxv += n; \
23947c4ee5bcSRichard Henderson         put_user_ual(val, u_auxv); u_auxv += n; \
239553a5960aSpbrook     } while(0)
23962f619698Sbellard 
239782991bedSPeter Maydell #ifdef ARCH_DLINFO
239882991bedSPeter Maydell     /*
239982991bedSPeter Maydell      * ARCH_DLINFO must come first so platform specific code can enforce
240082991bedSPeter Maydell      * special alignment requirements on the AUXV if necessary (eg. PPC).
240182991bedSPeter Maydell      */
240282991bedSPeter Maydell     ARCH_DLINFO;
240382991bedSPeter Maydell #endif
2404f516511eSPeter Maydell     /* There must be exactly DLINFO_ITEMS entries here, or the assert
2405f516511eSPeter Maydell      * on info->auxv_len will trigger.
2406f516511eSPeter Maydell      */
24078e62a717SRichard Henderson     NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
2408992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
2409992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
241033143c44SLaurent Vivier     if ((info->alignment & ~qemu_host_page_mask) != 0) {
241133143c44SLaurent Vivier         /* Target doesn't support host page size alignment */
241233143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
241333143c44SLaurent Vivier     } else {
241433143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(MAX(TARGET_PAGE_SIZE,
241533143c44SLaurent Vivier                                                qemu_host_page_size)));
241633143c44SLaurent Vivier     }
24178e62a717SRichard Henderson     NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
2418992f48a0Sblueswir1     NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
24198e62a717SRichard Henderson     NEW_AUX_ENT(AT_ENTRY, info->entry);
2420992f48a0Sblueswir1     NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
2421992f48a0Sblueswir1     NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
2422992f48a0Sblueswir1     NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
2423992f48a0Sblueswir1     NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
2424992f48a0Sblueswir1     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
2425a07c67dfSpbrook     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
242614322badSLaurent ALFONSI     NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
2427444cd5c3SMarco A L Barbosa     NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
2428e0d1673dSLirong Yuan     NEW_AUX_ENT(AT_EXECFN, info->file_string);
242914322badSLaurent ALFONSI 
2430ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2431ad6919dcSPeter Maydell     NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
2432ad6919dcSPeter Maydell #endif
2433ad6919dcSPeter Maydell 
2434fcdc0ab4SJiaxun Yang     if (u_base_platform) {
2435fcdc0ab4SJiaxun Yang         NEW_AUX_ENT(AT_BASE_PLATFORM, u_base_platform);
2436fcdc0ab4SJiaxun Yang     }
24377c4ee5bcSRichard Henderson     if (u_platform) {
243853a5960aSpbrook         NEW_AUX_ENT(AT_PLATFORM, u_platform);
24397c4ee5bcSRichard Henderson     }
24407c4ee5bcSRichard Henderson     NEW_AUX_ENT (AT_NULL, 0);
2441f5155289Sbellard #undef NEW_AUX_ENT
2442f5155289Sbellard 
2443f516511eSPeter Maydell     /* Check that our initial calculation of the auxv length matches how much
2444f516511eSPeter Maydell      * we actually put into it.
2445f516511eSPeter Maydell      */
2446f516511eSPeter Maydell     assert(info->auxv_len == u_auxv - info->saved_auxv);
2447edf8e2afSMika Westerberg 
24487c4ee5bcSRichard Henderson     put_user_ual(argc, u_argc);
24497c4ee5bcSRichard Henderson 
24507c4ee5bcSRichard Henderson     p = info->arg_strings;
24517c4ee5bcSRichard Henderson     for (i = 0; i < argc; ++i) {
24527c4ee5bcSRichard Henderson         put_user_ual(p, u_argv);
24537c4ee5bcSRichard Henderson         u_argv += n;
24547c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
24557c4ee5bcSRichard Henderson     }
24567c4ee5bcSRichard Henderson     put_user_ual(0, u_argv);
24577c4ee5bcSRichard Henderson 
24587c4ee5bcSRichard Henderson     p = info->env_strings;
24597c4ee5bcSRichard Henderson     for (i = 0; i < envc; ++i) {
24607c4ee5bcSRichard Henderson         put_user_ual(p, u_envp);
24617c4ee5bcSRichard Henderson         u_envp += n;
24627c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
24637c4ee5bcSRichard Henderson     }
24647c4ee5bcSRichard Henderson     put_user_ual(0, u_envp);
24657c4ee5bcSRichard Henderson 
246631e31b8aSbellard     return sp;
246731e31b8aSbellard }
246831e31b8aSbellard 
2469f5ef0e51SRichard Henderson #if defined(HI_COMMPAGE)
2470eee816c0SRichard Henderson #define LO_COMMPAGE -1
2471f5ef0e51SRichard Henderson #elif defined(LO_COMMPAGE)
247266346fafSRichard Henderson #define HI_COMMPAGE 0
2473f5ef0e51SRichard Henderson #else
2474f5ef0e51SRichard Henderson #define HI_COMMPAGE 0
2475eee816c0SRichard Henderson #define LO_COMMPAGE -1
2476d461b73eSRichard Henderson #ifndef INIT_GUEST_COMMPAGE
2477ee947430SAlex Bennée #define init_guest_commpage() true
2478ee947430SAlex Bennée #endif
2479d461b73eSRichard Henderson #endif
2480ee947430SAlex Bennée 
2481ee947430SAlex Bennée static void pgb_fail_in_use(const char *image_name)
2482ee947430SAlex Bennée {
2483ee947430SAlex Bennée     error_report("%s: requires virtual address space that is in use "
2484ee947430SAlex Bennée                  "(omit the -B option or choose a different value)",
2485ee947430SAlex Bennée                  image_name);
2486ee947430SAlex Bennée     exit(EXIT_FAILURE);
2487ee947430SAlex Bennée }
2488ee947430SAlex Bennée 
2489ee947430SAlex Bennée static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr,
2490ee947430SAlex Bennée                                 abi_ulong guest_hiaddr, long align)
2491ee947430SAlex Bennée {
2492ee947430SAlex Bennée     const int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
2493ee947430SAlex Bennée     void *addr, *test;
2494ee947430SAlex Bennée 
2495ee947430SAlex Bennée     if (!QEMU_IS_ALIGNED(guest_base, align)) {
24965ca870b9SRichard Henderson         fprintf(stderr, "Requested guest base %p does not satisfy "
2497ee947430SAlex Bennée                 "host minimum alignment (0x%lx)\n",
24985ca870b9SRichard Henderson                 (void *)guest_base, align);
2499ee947430SAlex Bennée         exit(EXIT_FAILURE);
2500ee947430SAlex Bennée     }
2501ee947430SAlex Bennée 
2502ee947430SAlex Bennée     /* Sanity check the guest binary. */
2503ee947430SAlex Bennée     if (reserved_va) {
2504ee947430SAlex Bennée         if (guest_hiaddr > reserved_va) {
2505ee947430SAlex Bennée             error_report("%s: requires more than reserved virtual "
2506ee947430SAlex Bennée                          "address space (0x%" PRIx64 " > 0x%lx)",
2507ee947430SAlex Bennée                          image_name, (uint64_t)guest_hiaddr, reserved_va);
2508ee947430SAlex Bennée             exit(EXIT_FAILURE);
2509ee947430SAlex Bennée         }
2510ee947430SAlex Bennée     } else {
2511a932eec4SAlex Bennée #if HOST_LONG_BITS < TARGET_ABI_BITS
2512ee947430SAlex Bennée         if ((guest_hiaddr - guest_base) > ~(uintptr_t)0) {
2513ee947430SAlex Bennée             error_report("%s: requires more virtual address space "
2514ee947430SAlex Bennée                          "than the host can provide (0x%" PRIx64 ")",
2515ee947430SAlex Bennée                          image_name, (uint64_t)guest_hiaddr - guest_base);
2516ee947430SAlex Bennée             exit(EXIT_FAILURE);
2517ee947430SAlex Bennée         }
2518a932eec4SAlex Bennée #endif
2519ee947430SAlex Bennée     }
2520ee947430SAlex Bennée 
2521ee947430SAlex Bennée     /*
2522ee947430SAlex Bennée      * Expand the allocation to the entire reserved_va.
2523ee947430SAlex Bennée      * Exclude the mmap_min_addr hole.
2524ee947430SAlex Bennée      */
2525ee947430SAlex Bennée     if (reserved_va) {
2526ee947430SAlex Bennée         guest_loaddr = (guest_base >= mmap_min_addr ? 0
2527ee947430SAlex Bennée                         : mmap_min_addr - guest_base);
2528ee947430SAlex Bennée         guest_hiaddr = reserved_va;
2529ee947430SAlex Bennée     }
2530ee947430SAlex Bennée 
2531ee947430SAlex Bennée     /* Reserve the address space for the binary, or reserved_va. */
25323e8f1628SRichard Henderson     test = g2h_untagged(guest_loaddr);
2533ee947430SAlex Bennée     addr = mmap(test, guest_hiaddr - guest_loaddr, PROT_NONE, flags, -1, 0);
2534ee947430SAlex Bennée     if (test != addr) {
2535ee947430SAlex Bennée         pgb_fail_in_use(image_name);
2536ee947430SAlex Bennée     }
2537e7588237SAlex Bennée     qemu_log_mask(CPU_LOG_PAGE,
2538e7588237SAlex Bennée                   "%s: base @ %p for " TARGET_ABI_FMT_ld " bytes\n",
2539e7588237SAlex Bennée                   __func__, addr, guest_hiaddr - guest_loaddr);
2540ee947430SAlex Bennée }
2541ee947430SAlex Bennée 
2542ad592e37SAlex Bennée /**
2543ad592e37SAlex Bennée  * pgd_find_hole_fallback: potential mmap address
2544ad592e37SAlex Bennée  * @guest_size: size of available space
2545ad592e37SAlex Bennée  * @brk: location of break
2546ad592e37SAlex Bennée  * @align: memory alignment
2547ad592e37SAlex Bennée  *
2548ad592e37SAlex Bennée  * This is a fallback method for finding a hole in the host address
2549ad592e37SAlex Bennée  * space if we don't have the benefit of being able to access
2550ad592e37SAlex Bennée  * /proc/self/map. It can potentially take a very long time as we can
2551ad592e37SAlex Bennée  * only dumbly iterate up the host address space seeing if the
2552ad592e37SAlex Bennée  * allocation would work.
2553ad592e37SAlex Bennée  */
25545c3e87f3SAlex Bennée static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk,
25555c3e87f3SAlex Bennée                                         long align, uintptr_t offset)
2556ad592e37SAlex Bennée {
2557ad592e37SAlex Bennée     uintptr_t base;
2558ad592e37SAlex Bennée 
2559ad592e37SAlex Bennée     /* Start (aligned) at the bottom and work our way up */
2560ad592e37SAlex Bennée     base = ROUND_UP(mmap_min_addr, align);
2561ad592e37SAlex Bennée 
2562ad592e37SAlex Bennée     while (true) {
2563ad592e37SAlex Bennée         uintptr_t align_start, end;
2564ad592e37SAlex Bennée         align_start = ROUND_UP(base, align);
25655c3e87f3SAlex Bennée         end = align_start + guest_size + offset;
2566ad592e37SAlex Bennée 
2567ad592e37SAlex Bennée         /* if brk is anywhere in the range give ourselves some room to grow. */
2568ad592e37SAlex Bennée         if (align_start <= brk && brk < end) {
2569ad592e37SAlex Bennée             base = brk + (16 * MiB);
2570ad592e37SAlex Bennée             continue;
2571ad592e37SAlex Bennée         } else if (align_start + guest_size < align_start) {
2572ad592e37SAlex Bennée             /* we have run out of space */
2573ad592e37SAlex Bennée             return -1;
2574ad592e37SAlex Bennée         } else {
25752667e069SAlex Bennée             int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE |
25762667e069SAlex Bennée                 MAP_FIXED_NOREPLACE;
2577ad592e37SAlex Bennée             void * mmap_start = mmap((void *) align_start, guest_size,
2578ad592e37SAlex Bennée                                      PROT_NONE, flags, -1, 0);
2579ad592e37SAlex Bennée             if (mmap_start != MAP_FAILED) {
25807e588fbcSVincent Fazio                 munmap(mmap_start, guest_size);
2581934eed51SVincent Fazio                 if (mmap_start == (void *) align_start) {
2582e7588237SAlex Bennée                     qemu_log_mask(CPU_LOG_PAGE,
2583e7588237SAlex Bennée                                   "%s: base @ %p for %" PRIdPTR" bytes\n",
2584e7588237SAlex Bennée                                   __func__, mmap_start + offset, guest_size);
25855c3e87f3SAlex Bennée                     return (uintptr_t) mmap_start + offset;
2586ad592e37SAlex Bennée                 }
25872667e069SAlex Bennée             }
2588ad592e37SAlex Bennée             base += qemu_host_page_size;
2589ad592e37SAlex Bennée         }
2590ad592e37SAlex Bennée     }
2591ad592e37SAlex Bennée }
2592ad592e37SAlex Bennée 
2593ee947430SAlex Bennée /* Return value for guest_base, or -1 if no hole found. */
2594ee947430SAlex Bennée static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size,
25955c3e87f3SAlex Bennée                                long align, uintptr_t offset)
2596ee947430SAlex Bennée {
2597ee947430SAlex Bennée     GSList *maps, *iter;
2598ee947430SAlex Bennée     uintptr_t this_start, this_end, next_start, brk;
2599ee947430SAlex Bennée     intptr_t ret = -1;
2600ee947430SAlex Bennée 
2601ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_loaddr, align));
2602ee947430SAlex Bennée 
2603ee947430SAlex Bennée     maps = read_self_maps();
2604ee947430SAlex Bennée 
2605ee947430SAlex Bennée     /* Read brk after we've read the maps, which will malloc. */
2606ee947430SAlex Bennée     brk = (uintptr_t)sbrk(0);
2607ee947430SAlex Bennée 
2608ad592e37SAlex Bennée     if (!maps) {
2609190674f3SAlex Bennée         return pgd_find_hole_fallback(guest_size, brk, align, offset);
2610ad592e37SAlex Bennée     }
2611ad592e37SAlex Bennée 
2612ee947430SAlex Bennée     /* The first hole is before the first map entry. */
2613ee947430SAlex Bennée     this_start = mmap_min_addr;
2614ee947430SAlex Bennée 
2615ee947430SAlex Bennée     for (iter = maps; iter;
2616ee947430SAlex Bennée          this_start = next_start, iter = g_slist_next(iter)) {
2617ee947430SAlex Bennée         uintptr_t align_start, hole_size;
2618ee947430SAlex Bennée 
2619ee947430SAlex Bennée         this_end = ((MapInfo *)iter->data)->start;
2620ee947430SAlex Bennée         next_start = ((MapInfo *)iter->data)->end;
26215c3e87f3SAlex Bennée         align_start = ROUND_UP(this_start + offset, align);
2622ee947430SAlex Bennée 
2623ee947430SAlex Bennée         /* Skip holes that are too small. */
2624ee947430SAlex Bennée         if (align_start >= this_end) {
2625ee947430SAlex Bennée             continue;
2626ee947430SAlex Bennée         }
2627ee947430SAlex Bennée         hole_size = this_end - align_start;
2628ee947430SAlex Bennée         if (hole_size < guest_size) {
2629ee947430SAlex Bennée             continue;
2630ee947430SAlex Bennée         }
2631ee947430SAlex Bennée 
2632ee947430SAlex Bennée         /* If this hole contains brk, give ourselves some room to grow. */
2633ee947430SAlex Bennée         if (this_start <= brk && brk < this_end) {
2634ee947430SAlex Bennée             hole_size -= guest_size;
2635ee947430SAlex Bennée             if (sizeof(uintptr_t) == 8 && hole_size >= 1 * GiB) {
2636ee947430SAlex Bennée                 align_start += 1 * GiB;
2637ee947430SAlex Bennée             } else if (hole_size >= 16 * MiB) {
2638ee947430SAlex Bennée                 align_start += 16 * MiB;
2639ee947430SAlex Bennée             } else {
2640ee947430SAlex Bennée                 align_start = (this_end - guest_size) & -align;
2641ee947430SAlex Bennée                 if (align_start < this_start) {
2642ee947430SAlex Bennée                     continue;
2643ee947430SAlex Bennée                 }
2644ee947430SAlex Bennée             }
2645ee947430SAlex Bennée         }
2646ee947430SAlex Bennée 
2647ee947430SAlex Bennée         /* Record the lowest successful match. */
2648ee947430SAlex Bennée         if (ret < 0) {
2649190674f3SAlex Bennée             ret = align_start;
2650ee947430SAlex Bennée         }
2651ee947430SAlex Bennée         /* If this hole contains the identity map, select it. */
2652ee947430SAlex Bennée         if (align_start <= guest_loaddr &&
2653ee947430SAlex Bennée             guest_loaddr + guest_size <= this_end) {
2654ee947430SAlex Bennée             ret = 0;
2655ee947430SAlex Bennée         }
2656ee947430SAlex Bennée         /* If this hole ends above the identity map, stop looking. */
2657ee947430SAlex Bennée         if (this_end >= guest_loaddr) {
2658ee947430SAlex Bennée             break;
2659ee947430SAlex Bennée         }
2660ee947430SAlex Bennée     }
2661ee947430SAlex Bennée     free_self_maps(maps);
2662ee947430SAlex Bennée 
2663e7588237SAlex Bennée     if (ret != -1) {
2664e7588237SAlex Bennée         qemu_log_mask(CPU_LOG_PAGE, "%s: base @ %" PRIxPTR
2665e7588237SAlex Bennée                       " for %" PRIuPTR " bytes\n",
2666e7588237SAlex Bennée                       __func__, ret, guest_size);
2667e7588237SAlex Bennée     }
2668e7588237SAlex Bennée 
2669ee947430SAlex Bennée     return ret;
2670ee947430SAlex Bennée }
2671ee947430SAlex Bennée 
2672ee947430SAlex Bennée static void pgb_static(const char *image_name, abi_ulong orig_loaddr,
2673ee947430SAlex Bennée                        abi_ulong orig_hiaddr, long align)
2674ee947430SAlex Bennée {
2675ee947430SAlex Bennée     uintptr_t loaddr = orig_loaddr;
2676ee947430SAlex Bennée     uintptr_t hiaddr = orig_hiaddr;
26775c3e87f3SAlex Bennée     uintptr_t offset = 0;
2678ee947430SAlex Bennée     uintptr_t addr;
2679ee947430SAlex Bennée 
2680ee947430SAlex Bennée     if (hiaddr != orig_hiaddr) {
2681ee947430SAlex Bennée         error_report("%s: requires virtual address space that the "
2682ee947430SAlex Bennée                      "host cannot provide (0x%" PRIx64 ")",
2683ee947430SAlex Bennée                      image_name, (uint64_t)orig_hiaddr);
2684ee947430SAlex Bennée         exit(EXIT_FAILURE);
2685ee947430SAlex Bennée     }
2686ee947430SAlex Bennée 
2687ee947430SAlex Bennée     loaddr &= -align;
268866346fafSRichard Henderson     if (HI_COMMPAGE) {
2689ee947430SAlex Bennée         /*
2690ee947430SAlex Bennée          * Extend the allocation to include the commpage.
26915c3e87f3SAlex Bennée          * For a 64-bit host, this is just 4GiB; for a 32-bit host we
26925c3e87f3SAlex Bennée          * need to ensure there is space bellow the guest_base so we
26935c3e87f3SAlex Bennée          * can map the commpage in the place needed when the address
26945c3e87f3SAlex Bennée          * arithmetic wraps around.
2695ee947430SAlex Bennée          */
2696ee947430SAlex Bennée         if (sizeof(uintptr_t) == 8 || loaddr >= 0x80000000u) {
2697ee947430SAlex Bennée             hiaddr = (uintptr_t) 4 << 30;
2698ee947430SAlex Bennée         } else {
269966346fafSRichard Henderson             offset = -(HI_COMMPAGE & -align);
2700ee947430SAlex Bennée         }
2701eee816c0SRichard Henderson     } else if (LO_COMMPAGE != -1) {
2702f5ef0e51SRichard Henderson         loaddr = MIN(loaddr, LO_COMMPAGE & -align);
2703ee947430SAlex Bennée     }
2704ee947430SAlex Bennée 
27055c3e87f3SAlex Bennée     addr = pgb_find_hole(loaddr, hiaddr - loaddr, align, offset);
2706ee947430SAlex Bennée     if (addr == -1) {
2707ee947430SAlex Bennée         /*
270866346fafSRichard Henderson          * If HI_COMMPAGE, there *might* be a non-consecutive allocation
2709ee947430SAlex Bennée          * that can satisfy both.  But as the normal arm32 link base address
2710ee947430SAlex Bennée          * is ~32k, and we extend down to include the commpage, making the
2711ee947430SAlex Bennée          * overhead only ~96k, this is unlikely.
2712ee947430SAlex Bennée          */
2713ee947430SAlex Bennée         error_report("%s: Unable to allocate %#zx bytes of "
2714ee947430SAlex Bennée                      "virtual address space", image_name,
2715ee947430SAlex Bennée                      (size_t)(hiaddr - loaddr));
2716ee947430SAlex Bennée         exit(EXIT_FAILURE);
2717ee947430SAlex Bennée     }
2718ee947430SAlex Bennée 
2719ee947430SAlex Bennée     guest_base = addr;
2720e7588237SAlex Bennée 
2721e7588237SAlex Bennée     qemu_log_mask(CPU_LOG_PAGE, "%s: base @ %"PRIxPTR" for %" PRIuPTR" bytes\n",
2722e7588237SAlex Bennée                   __func__, addr, hiaddr - loaddr);
2723ee947430SAlex Bennée }
2724ee947430SAlex Bennée 
2725ee947430SAlex Bennée static void pgb_dynamic(const char *image_name, long align)
2726ee947430SAlex Bennée {
2727ee947430SAlex Bennée     /*
2728ee947430SAlex Bennée      * The executable is dynamic and does not require a fixed address.
2729ee947430SAlex Bennée      * All we need is a commpage that satisfies align.
2730ee947430SAlex Bennée      * If we do not need a commpage, leave guest_base == 0.
2731ee947430SAlex Bennée      */
273266346fafSRichard Henderson     if (HI_COMMPAGE) {
2733ee947430SAlex Bennée         uintptr_t addr, commpage;
2734ee947430SAlex Bennée 
2735ee947430SAlex Bennée         /* 64-bit hosts should have used reserved_va. */
2736ee947430SAlex Bennée         assert(sizeof(uintptr_t) == 4);
2737ee947430SAlex Bennée 
2738ee947430SAlex Bennée         /*
2739ee947430SAlex Bennée          * By putting the commpage at the first hole, that puts guest_base
2740ee947430SAlex Bennée          * just above that, and maximises the positive guest addresses.
2741ee947430SAlex Bennée          */
274266346fafSRichard Henderson         commpage = HI_COMMPAGE & -align;
27435c3e87f3SAlex Bennée         addr = pgb_find_hole(commpage, -commpage, align, 0);
2744ee947430SAlex Bennée         assert(addr != -1);
2745ee947430SAlex Bennée         guest_base = addr;
2746ee947430SAlex Bennée     }
2747ee947430SAlex Bennée }
2748ee947430SAlex Bennée 
2749ee947430SAlex Bennée static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr,
2750ee947430SAlex Bennée                             abi_ulong guest_hiaddr, long align)
2751ee947430SAlex Bennée {
2752c1f6ad79SAlex Bennée     int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
2753ee947430SAlex Bennée     void *addr, *test;
2754ee947430SAlex Bennée 
2755ee947430SAlex Bennée     if (guest_hiaddr > reserved_va) {
2756ee947430SAlex Bennée         error_report("%s: requires more than reserved virtual "
2757ee947430SAlex Bennée                      "address space (0x%" PRIx64 " > 0x%lx)",
2758ee947430SAlex Bennée                      image_name, (uint64_t)guest_hiaddr, reserved_va);
2759ee947430SAlex Bennée         exit(EXIT_FAILURE);
2760ee947430SAlex Bennée     }
2761ee947430SAlex Bennée 
2762ee947430SAlex Bennée     /* Widen the "image" to the entire reserved address space. */
2763ee947430SAlex Bennée     pgb_static(image_name, 0, reserved_va, align);
2764ee947430SAlex Bennée 
27652667e069SAlex Bennée     /* osdep.h defines this as 0 if it's missing */
2766c1f6ad79SAlex Bennée     flags |= MAP_FIXED_NOREPLACE;
2767c1f6ad79SAlex Bennée 
2768ee947430SAlex Bennée     /* Reserve the memory on the host. */
2769ee947430SAlex Bennée     assert(guest_base != 0);
27703e8f1628SRichard Henderson     test = g2h_untagged(0);
2771ee947430SAlex Bennée     addr = mmap(test, reserved_va, PROT_NONE, flags, -1, 0);
2772fb730c86SAlex Bennée     if (addr == MAP_FAILED || addr != test) {
2773ee947430SAlex Bennée         error_report("Unable to reserve 0x%lx bytes of virtual address "
2774fb730c86SAlex Bennée                      "space at %p (%s) for use as guest address space (check your "
2775fb730c86SAlex Bennée                      "virtual memory ulimit setting, min_mmap_addr or reserve less "
2776fb730c86SAlex Bennée                      "using -R option)", reserved_va, test, strerror(errno));
2777ee947430SAlex Bennée         exit(EXIT_FAILURE);
2778ee947430SAlex Bennée     }
2779e7588237SAlex Bennée 
2780e7588237SAlex Bennée     qemu_log_mask(CPU_LOG_PAGE, "%s: base @ %p for %lu bytes\n",
2781e7588237SAlex Bennée                   __func__, addr, reserved_va);
2782ee947430SAlex Bennée }
2783ee947430SAlex Bennée 
2784ee947430SAlex Bennée void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
2785ee947430SAlex Bennée                       abi_ulong guest_hiaddr)
2786dce10401SMeador Inge {
278730ab9ef2SRichard Henderson     /* In order to use host shmat, we must be able to honor SHMLBA.  */
2788ee947430SAlex Bennée     uintptr_t align = MAX(SHMLBA, qemu_host_page_size);
2789dce10401SMeador Inge 
2790ee947430SAlex Bennée     if (have_guest_base) {
2791ee947430SAlex Bennée         pgb_have_guest_base(image_name, guest_loaddr, guest_hiaddr, align);
2792ee947430SAlex Bennée     } else if (reserved_va) {
2793ee947430SAlex Bennée         pgb_reserved_va(image_name, guest_loaddr, guest_hiaddr, align);
2794ee947430SAlex Bennée     } else if (guest_loaddr) {
2795ee947430SAlex Bennée         pgb_static(image_name, guest_loaddr, guest_hiaddr, align);
2796293f2060SLuke Shumaker     } else {
2797ee947430SAlex Bennée         pgb_dynamic(image_name, align);
2798806d1021SMeador Inge     }
2799806d1021SMeador Inge 
2800ee947430SAlex Bennée     /* Reserve and initialize the commpage. */
2801ee947430SAlex Bennée     if (!init_guest_commpage()) {
2802ee947430SAlex Bennée         /*
2803ee947430SAlex Bennée          * With have_guest_base, the user has selected the address and
2804ee947430SAlex Bennée          * we are trying to work with that.  Otherwise, we have selected
2805ee947430SAlex Bennée          * free space and init_guest_commpage must succeeded.
28067ad75eeaSLuke Shumaker          */
2807ee947430SAlex Bennée         assert(have_guest_base);
2808ee947430SAlex Bennée         pgb_fail_in_use(image_name);
2809dce10401SMeador Inge     }
2810dce10401SMeador Inge 
2811ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_base, align));
2812ee947430SAlex Bennée     qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space "
2813ee947430SAlex Bennée                   "@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
2814dce10401SMeador Inge }
2815dce10401SMeador Inge 
281683f990ebSRichard Henderson enum {
281783f990ebSRichard Henderson     /* The string "GNU\0" as a magic number. */
281883f990ebSRichard Henderson     GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
281983f990ebSRichard Henderson     NOTE_DATA_SZ = 1 * KiB,
282083f990ebSRichard Henderson     NOTE_NAME_SZ = 4,
282183f990ebSRichard Henderson     ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
282283f990ebSRichard Henderson };
282383f990ebSRichard Henderson 
282483f990ebSRichard Henderson /*
282583f990ebSRichard Henderson  * Process a single gnu_property entry.
282683f990ebSRichard Henderson  * Return false for error.
282783f990ebSRichard Henderson  */
282883f990ebSRichard Henderson static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
282983f990ebSRichard Henderson                                struct image_info *info, bool have_prev_type,
283083f990ebSRichard Henderson                                uint32_t *prev_type, Error **errp)
283183f990ebSRichard Henderson {
283283f990ebSRichard Henderson     uint32_t pr_type, pr_datasz, step;
283383f990ebSRichard Henderson 
283483f990ebSRichard Henderson     if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
283583f990ebSRichard Henderson         goto error_data;
283683f990ebSRichard Henderson     }
283783f990ebSRichard Henderson     datasz -= *off;
283883f990ebSRichard Henderson     data += *off / sizeof(uint32_t);
283983f990ebSRichard Henderson 
284083f990ebSRichard Henderson     if (datasz < 2 * sizeof(uint32_t)) {
284183f990ebSRichard Henderson         goto error_data;
284283f990ebSRichard Henderson     }
284383f990ebSRichard Henderson     pr_type = data[0];
284483f990ebSRichard Henderson     pr_datasz = data[1];
284583f990ebSRichard Henderson     data += 2;
284683f990ebSRichard Henderson     datasz -= 2 * sizeof(uint32_t);
284783f990ebSRichard Henderson     step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
284883f990ebSRichard Henderson     if (step > datasz) {
284983f990ebSRichard Henderson         goto error_data;
285083f990ebSRichard Henderson     }
285183f990ebSRichard Henderson 
285283f990ebSRichard Henderson     /* Properties are supposed to be unique and sorted on pr_type. */
285383f990ebSRichard Henderson     if (have_prev_type && pr_type <= *prev_type) {
285483f990ebSRichard Henderson         if (pr_type == *prev_type) {
285583f990ebSRichard Henderson             error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
285683f990ebSRichard Henderson         } else {
285783f990ebSRichard Henderson             error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
285883f990ebSRichard Henderson         }
285983f990ebSRichard Henderson         return false;
286083f990ebSRichard Henderson     }
286183f990ebSRichard Henderson     *prev_type = pr_type;
286283f990ebSRichard Henderson 
286383f990ebSRichard Henderson     if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
286483f990ebSRichard Henderson         return false;
286583f990ebSRichard Henderson     }
286683f990ebSRichard Henderson 
286783f990ebSRichard Henderson     *off += 2 * sizeof(uint32_t) + step;
286883f990ebSRichard Henderson     return true;
286983f990ebSRichard Henderson 
287083f990ebSRichard Henderson  error_data:
287183f990ebSRichard Henderson     error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
287283f990ebSRichard Henderson     return false;
287383f990ebSRichard Henderson }
287483f990ebSRichard Henderson 
287583f990ebSRichard Henderson /* Process NT_GNU_PROPERTY_TYPE_0. */
287683f990ebSRichard Henderson static bool parse_elf_properties(int image_fd,
287783f990ebSRichard Henderson                                  struct image_info *info,
287883f990ebSRichard Henderson                                  const struct elf_phdr *phdr,
287983f990ebSRichard Henderson                                  char bprm_buf[BPRM_BUF_SIZE],
288083f990ebSRichard Henderson                                  Error **errp)
288183f990ebSRichard Henderson {
288283f990ebSRichard Henderson     union {
288383f990ebSRichard Henderson         struct elf_note nhdr;
288483f990ebSRichard Henderson         uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
288583f990ebSRichard Henderson     } note;
288683f990ebSRichard Henderson 
288783f990ebSRichard Henderson     int n, off, datasz;
288883f990ebSRichard Henderson     bool have_prev_type;
288983f990ebSRichard Henderson     uint32_t prev_type;
289083f990ebSRichard Henderson 
289183f990ebSRichard Henderson     /* Unless the arch requires properties, ignore them. */
289283f990ebSRichard Henderson     if (!ARCH_USE_GNU_PROPERTY) {
289383f990ebSRichard Henderson         return true;
289483f990ebSRichard Henderson     }
289583f990ebSRichard Henderson 
289683f990ebSRichard Henderson     /* If the properties are crazy large, that's too bad. */
289783f990ebSRichard Henderson     n = phdr->p_filesz;
289883f990ebSRichard Henderson     if (n > sizeof(note)) {
289983f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too large");
290083f990ebSRichard Henderson         return false;
290183f990ebSRichard Henderson     }
290283f990ebSRichard Henderson     if (n < sizeof(note.nhdr)) {
290383f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too small");
290483f990ebSRichard Henderson         return false;
290583f990ebSRichard Henderson     }
290683f990ebSRichard Henderson 
290783f990ebSRichard Henderson     if (phdr->p_offset + n <= BPRM_BUF_SIZE) {
290883f990ebSRichard Henderson         memcpy(&note, bprm_buf + phdr->p_offset, n);
290983f990ebSRichard Henderson     } else {
291083f990ebSRichard Henderson         ssize_t len = pread(image_fd, &note, n, phdr->p_offset);
291183f990ebSRichard Henderson         if (len != n) {
291283f990ebSRichard Henderson             error_setg_errno(errp, errno, "Error reading file header");
291383f990ebSRichard Henderson             return false;
291483f990ebSRichard Henderson         }
291583f990ebSRichard Henderson     }
291683f990ebSRichard Henderson 
291783f990ebSRichard Henderson     /*
291883f990ebSRichard Henderson      * The contents of a valid PT_GNU_PROPERTY is a sequence
291983f990ebSRichard Henderson      * of uint32_t -- swap them all now.
292083f990ebSRichard Henderson      */
292183f990ebSRichard Henderson #ifdef BSWAP_NEEDED
292283f990ebSRichard Henderson     for (int i = 0; i < n / 4; i++) {
292383f990ebSRichard Henderson         bswap32s(note.data + i);
292483f990ebSRichard Henderson     }
292583f990ebSRichard Henderson #endif
292683f990ebSRichard Henderson 
292783f990ebSRichard Henderson     /*
292883f990ebSRichard Henderson      * Note that nhdr is 3 words, and that the "name" described by namesz
292983f990ebSRichard Henderson      * immediately follows nhdr and is thus at the 4th word.  Further, all
293083f990ebSRichard Henderson      * of the inputs to the kernel's round_up are multiples of 4.
293183f990ebSRichard Henderson      */
293283f990ebSRichard Henderson     if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
293383f990ebSRichard Henderson         note.nhdr.n_namesz != NOTE_NAME_SZ ||
293483f990ebSRichard Henderson         note.data[3] != GNU0_MAGIC) {
293583f990ebSRichard Henderson         error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
293683f990ebSRichard Henderson         return false;
293783f990ebSRichard Henderson     }
293883f990ebSRichard Henderson     off = sizeof(note.nhdr) + NOTE_NAME_SZ;
293983f990ebSRichard Henderson 
294083f990ebSRichard Henderson     datasz = note.nhdr.n_descsz + off;
294183f990ebSRichard Henderson     if (datasz > n) {
294283f990ebSRichard Henderson         error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
294383f990ebSRichard Henderson         return false;
294483f990ebSRichard Henderson     }
294583f990ebSRichard Henderson 
294683f990ebSRichard Henderson     have_prev_type = false;
294783f990ebSRichard Henderson     prev_type = 0;
294883f990ebSRichard Henderson     while (1) {
294983f990ebSRichard Henderson         if (off == datasz) {
295083f990ebSRichard Henderson             return true;  /* end, exit ok */
295183f990ebSRichard Henderson         }
295283f990ebSRichard Henderson         if (!parse_elf_property(note.data, &off, datasz, info,
295383f990ebSRichard Henderson                                 have_prev_type, &prev_type, errp)) {
295483f990ebSRichard Henderson             return false;
295583f990ebSRichard Henderson         }
295683f990ebSRichard Henderson         have_prev_type = true;
295783f990ebSRichard Henderson     }
295883f990ebSRichard Henderson }
295983f990ebSRichard Henderson 
29608e62a717SRichard Henderson /* Load an ELF image into the address space.
296131e31b8aSbellard 
29628e62a717SRichard Henderson    IMAGE_NAME is the filename of the image, to use in error messages.
29638e62a717SRichard Henderson    IMAGE_FD is the open file descriptor for the image.
29648e62a717SRichard Henderson 
29658e62a717SRichard Henderson    BPRM_BUF is a copy of the beginning of the file; this of course
29668e62a717SRichard Henderson    contains the elf file header at offset 0.  It is assumed that this
29678e62a717SRichard Henderson    buffer is sufficiently aligned to present no problems to the host
29688e62a717SRichard Henderson    in accessing data at aligned offsets within the buffer.
29698e62a717SRichard Henderson 
29708e62a717SRichard Henderson    On return: INFO values will be filled in, as necessary or available.  */
29718e62a717SRichard Henderson 
29728e62a717SRichard Henderson static void load_elf_image(const char *image_name, int image_fd,
2973bf858897SRichard Henderson                            struct image_info *info, char **pinterp_name,
29749955ffacSRichard Henderson                            char bprm_buf[BPRM_BUF_SIZE])
297531e31b8aSbellard {
29768e62a717SRichard Henderson     struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
29778e62a717SRichard Henderson     struct elf_phdr *phdr;
29788e62a717SRichard Henderson     abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
2979e8384b37SRichard Henderson     int i, retval, prot_exec;
2980c7f17e7bSRichard Henderson     Error *err = NULL;
298131e31b8aSbellard 
29828e62a717SRichard Henderson     /* First of all, some simple consistency checks */
29838e62a717SRichard Henderson     if (!elf_check_ident(ehdr)) {
2984c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
29858e62a717SRichard Henderson         goto exit_errmsg;
29868e62a717SRichard Henderson     }
29878e62a717SRichard Henderson     bswap_ehdr(ehdr);
29888e62a717SRichard Henderson     if (!elf_check_ehdr(ehdr)) {
2989c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
29908e62a717SRichard Henderson         goto exit_errmsg;
299131e31b8aSbellard     }
299231e31b8aSbellard 
29938e62a717SRichard Henderson     i = ehdr->e_phnum * sizeof(struct elf_phdr);
29948e62a717SRichard Henderson     if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) {
29958e62a717SRichard Henderson         phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff);
29969955ffacSRichard Henderson     } else {
29978e62a717SRichard Henderson         phdr = (struct elf_phdr *) alloca(i);
29988e62a717SRichard Henderson         retval = pread(image_fd, phdr, i, ehdr->e_phoff);
29999955ffacSRichard Henderson         if (retval != i) {
30008e62a717SRichard Henderson             goto exit_read;
30019955ffacSRichard Henderson         }
300231e31b8aSbellard     }
30038e62a717SRichard Henderson     bswap_phdr(phdr, ehdr->e_phnum);
300409bfb054Sbellard 
30051af02e83SMike Frysinger     info->nsegs = 0;
30061af02e83SMike Frysinger     info->pt_dynamic_addr = 0;
30071af02e83SMike Frysinger 
300898c1076cSAlex Bennée     mmap_lock();
300998c1076cSAlex Bennée 
30108a1a5274SRichard Henderson     /*
30118a1a5274SRichard Henderson      * Find the maximum size of the image and allocate an appropriate
30128a1a5274SRichard Henderson      * amount of memory to handle that.  Locate the interpreter, if any.
30138a1a5274SRichard Henderson      */
3014682674b8SRichard Henderson     loaddr = -1, hiaddr = 0;
301533143c44SLaurent Vivier     info->alignment = 0;
3016872f3d04SRichard Henderson     info->exec_stack = EXSTACK_DEFAULT;
30178e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; ++i) {
30184d9d535aSRichard Henderson         struct elf_phdr *eppnt = phdr + i;
30194d9d535aSRichard Henderson         if (eppnt->p_type == PT_LOAD) {
30204d9d535aSRichard Henderson             abi_ulong a = eppnt->p_vaddr - eppnt->p_offset;
3021682674b8SRichard Henderson             if (a < loaddr) {
3022682674b8SRichard Henderson                 loaddr = a;
3023682674b8SRichard Henderson             }
30244d9d535aSRichard Henderson             a = eppnt->p_vaddr + eppnt->p_memsz;
3025682674b8SRichard Henderson             if (a > hiaddr) {
3026682674b8SRichard Henderson                 hiaddr = a;
3027682674b8SRichard Henderson             }
30281af02e83SMike Frysinger             ++info->nsegs;
30294d9d535aSRichard Henderson             info->alignment |= eppnt->p_align;
30308a1a5274SRichard Henderson         } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
30318a1a5274SRichard Henderson             g_autofree char *interp_name = NULL;
30328a1a5274SRichard Henderson 
30338a1a5274SRichard Henderson             if (*pinterp_name) {
3034c7f17e7bSRichard Henderson                 error_setg(&err, "Multiple PT_INTERP entries");
30358a1a5274SRichard Henderson                 goto exit_errmsg;
30368a1a5274SRichard Henderson             }
3037c7f17e7bSRichard Henderson 
30388a1a5274SRichard Henderson             interp_name = g_malloc(eppnt->p_filesz);
30398a1a5274SRichard Henderson 
30408a1a5274SRichard Henderson             if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
30418a1a5274SRichard Henderson                 memcpy(interp_name, bprm_buf + eppnt->p_offset,
30428a1a5274SRichard Henderson                        eppnt->p_filesz);
30438a1a5274SRichard Henderson             } else {
30448a1a5274SRichard Henderson                 retval = pread(image_fd, interp_name, eppnt->p_filesz,
30458a1a5274SRichard Henderson                                eppnt->p_offset);
30468a1a5274SRichard Henderson                 if (retval != eppnt->p_filesz) {
3047c7f17e7bSRichard Henderson                     goto exit_read;
30488a1a5274SRichard Henderson                 }
30498a1a5274SRichard Henderson             }
30508a1a5274SRichard Henderson             if (interp_name[eppnt->p_filesz - 1] != 0) {
3051c7f17e7bSRichard Henderson                 error_setg(&err, "Invalid PT_INTERP entry");
30528a1a5274SRichard Henderson                 goto exit_errmsg;
30538a1a5274SRichard Henderson             }
30548a1a5274SRichard Henderson             *pinterp_name = g_steal_pointer(&interp_name);
305583f990ebSRichard Henderson         } else if (eppnt->p_type == PT_GNU_PROPERTY) {
305683f990ebSRichard Henderson             if (!parse_elf_properties(image_fd, info, eppnt, bprm_buf, &err)) {
305783f990ebSRichard Henderson                 goto exit_errmsg;
305883f990ebSRichard Henderson             }
3059872f3d04SRichard Henderson         } else if (eppnt->p_type == PT_GNU_STACK) {
3060872f3d04SRichard Henderson             info->exec_stack = eppnt->p_flags & PF_X;
3061682674b8SRichard Henderson         }
3062682674b8SRichard Henderson     }
3063682674b8SRichard Henderson 
30646fd59449SRichard Henderson     if (pinterp_name != NULL) {
30656fd59449SRichard Henderson         /*
30666fd59449SRichard Henderson          * This is the main executable.
30676fd59449SRichard Henderson          *
30686fd59449SRichard Henderson          * Reserve extra space for brk.
30696fd59449SRichard Henderson          * We hold on to this space while placing the interpreter
30706fd59449SRichard Henderson          * and the stack, lest they be placed immediately after
30716fd59449SRichard Henderson          * the data segment and block allocation from the brk.
30726fd59449SRichard Henderson          *
307311d36727SAlex Bennée          * 16MB is chosen as "large enough" without being so large as
307411d36727SAlex Bennée          * to allow the result to not fit with a 32-bit guest on a
307511d36727SAlex Bennée          * 32-bit host. However some 64 bit guests (e.g. s390x)
307611d36727SAlex Bennée          * attempt to place their heap further ahead and currently
307711d36727SAlex Bennée          * nothing stops them smashing into QEMUs address space.
30786fd59449SRichard Henderson          */
307911d36727SAlex Bennée #if TARGET_LONG_BITS == 64
308011d36727SAlex Bennée         info->reserve_brk = 32 * MiB;
308111d36727SAlex Bennée #else
30826fd59449SRichard Henderson         info->reserve_brk = 16 * MiB;
308311d36727SAlex Bennée #endif
30846fd59449SRichard Henderson         hiaddr += info->reserve_brk;
30856fd59449SRichard Henderson 
30866fd59449SRichard Henderson         if (ehdr->e_type == ET_EXEC) {
30876fd59449SRichard Henderson             /*
30886fd59449SRichard Henderson              * Make sure that the low address does not conflict with
30896fd59449SRichard Henderson              * MMAP_MIN_ADDR or the QEMU application itself.
30906fd59449SRichard Henderson              */
30916fd59449SRichard Henderson             probe_guest_base(image_name, loaddr, hiaddr);
3092ee947430SAlex Bennée         } else {
3093ee947430SAlex Bennée             /*
3094ee947430SAlex Bennée              * The binary is dynamic, but we still need to
3095ee947430SAlex Bennée              * select guest_base.  In this case we pass a size.
3096ee947430SAlex Bennée              */
3097ee947430SAlex Bennée             probe_guest_base(image_name, 0, hiaddr - loaddr);
30986fd59449SRichard Henderson         }
30996fd59449SRichard Henderson     }
31006fd59449SRichard Henderson 
31016fd59449SRichard Henderson     /*
31026fd59449SRichard Henderson      * Reserve address space for all of this.
31036fd59449SRichard Henderson      *
31046fd59449SRichard Henderson      * In the case of ET_EXEC, we supply MAP_FIXED so that we get
31056fd59449SRichard Henderson      * exactly the address range that is required.
31066fd59449SRichard Henderson      *
31076fd59449SRichard Henderson      * Otherwise this is ET_DYN, and we are searching for a location
31086fd59449SRichard Henderson      * that can hold the memory space required.  If the image is
31096fd59449SRichard Henderson      * pre-linked, LOADDR will be non-zero, and the kernel should
31106fd59449SRichard Henderson      * honor that address if it happens to be free.
31116fd59449SRichard Henderson      *
31126fd59449SRichard Henderson      * In both cases, we will overwrite pages in this range with mappings
31136fd59449SRichard Henderson      * from the executable.
31146fd59449SRichard Henderson      */
3115682674b8SRichard Henderson     load_addr = target_mmap(loaddr, hiaddr - loaddr, PROT_NONE,
31166fd59449SRichard Henderson                             MAP_PRIVATE | MAP_ANON | MAP_NORESERVE |
31176fd59449SRichard Henderson                             (ehdr->e_type == ET_EXEC ? MAP_FIXED : 0),
311809bfb054Sbellard                             -1, 0);
3119682674b8SRichard Henderson     if (load_addr == -1) {
3120c7f17e7bSRichard Henderson         goto exit_mmap;
312109bfb054Sbellard     }
3122682674b8SRichard Henderson     load_bias = load_addr - loaddr;
312309bfb054Sbellard 
3124a99856cdSChristophe Lyon     if (elf_is_fdpic(ehdr)) {
31251af02e83SMike Frysinger         struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
31267267c094SAnthony Liguori             g_malloc(sizeof(*loadsegs) * info->nsegs);
31271af02e83SMike Frysinger 
31281af02e83SMike Frysinger         for (i = 0; i < ehdr->e_phnum; ++i) {
31291af02e83SMike Frysinger             switch (phdr[i].p_type) {
31301af02e83SMike Frysinger             case PT_DYNAMIC:
31311af02e83SMike Frysinger                 info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
31321af02e83SMike Frysinger                 break;
31331af02e83SMike Frysinger             case PT_LOAD:
31341af02e83SMike Frysinger                 loadsegs->addr = phdr[i].p_vaddr + load_bias;
31351af02e83SMike Frysinger                 loadsegs->p_vaddr = phdr[i].p_vaddr;
31361af02e83SMike Frysinger                 loadsegs->p_memsz = phdr[i].p_memsz;
31371af02e83SMike Frysinger                 ++loadsegs;
31381af02e83SMike Frysinger                 break;
31391af02e83SMike Frysinger             }
31401af02e83SMike Frysinger         }
31411af02e83SMike Frysinger     }
31421af02e83SMike Frysinger 
31438e62a717SRichard Henderson     info->load_bias = load_bias;
3144dc12567aSJosh Kunz     info->code_offset = load_bias;
3145dc12567aSJosh Kunz     info->data_offset = load_bias;
31468e62a717SRichard Henderson     info->load_addr = load_addr;
31478e62a717SRichard Henderson     info->entry = ehdr->e_entry + load_bias;
31488e62a717SRichard Henderson     info->start_code = -1;
31498e62a717SRichard Henderson     info->end_code = 0;
31508e62a717SRichard Henderson     info->start_data = -1;
31518e62a717SRichard Henderson     info->end_data = 0;
31528e62a717SRichard Henderson     info->brk = 0;
3153d8fd2954SPaul Brook     info->elf_flags = ehdr->e_flags;
31548e62a717SRichard Henderson 
3155e8384b37SRichard Henderson     prot_exec = PROT_EXEC;
3156e8384b37SRichard Henderson #ifdef TARGET_AARCH64
3157e8384b37SRichard Henderson     /*
3158e8384b37SRichard Henderson      * If the BTI feature is present, this indicates that the executable
3159e8384b37SRichard Henderson      * pages of the startup binary should be mapped with PROT_BTI, so that
3160e8384b37SRichard Henderson      * branch targets are enforced.
3161e8384b37SRichard Henderson      *
3162e8384b37SRichard Henderson      * The startup binary is either the interpreter or the static executable.
3163e8384b37SRichard Henderson      * The interpreter is responsible for all pages of a dynamic executable.
3164e8384b37SRichard Henderson      *
3165e8384b37SRichard Henderson      * Elf notes are backward compatible to older cpus.
3166e8384b37SRichard Henderson      * Do not enable BTI unless it is supported.
3167e8384b37SRichard Henderson      */
3168e8384b37SRichard Henderson     if ((info->note_flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
3169e8384b37SRichard Henderson         && (pinterp_name == NULL || *pinterp_name == 0)
3170e8384b37SRichard Henderson         && cpu_isar_feature(aa64_bti, ARM_CPU(thread_cpu))) {
3171e8384b37SRichard Henderson         prot_exec |= TARGET_PROT_BTI;
3172e8384b37SRichard Henderson     }
3173e8384b37SRichard Henderson #endif
3174e8384b37SRichard Henderson 
31758e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; i++) {
31768e62a717SRichard Henderson         struct elf_phdr *eppnt = phdr + i;
317731e31b8aSbellard         if (eppnt->p_type == PT_LOAD) {
317894894ff2SShivaprasad G Bhat             abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em, vaddr_len;
317931e31b8aSbellard             int elf_prot = 0;
318031e31b8aSbellard 
3181e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_R) {
3182e5eaf570SRichard Henderson                 elf_prot |= PROT_READ;
3183e5eaf570SRichard Henderson             }
3184e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_W) {
3185e5eaf570SRichard Henderson                 elf_prot |= PROT_WRITE;
3186e5eaf570SRichard Henderson             }
3187e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_X) {
3188e8384b37SRichard Henderson                 elf_prot |= prot_exec;
3189e5eaf570SRichard Henderson             }
319031e31b8aSbellard 
3191682674b8SRichard Henderson             vaddr = load_bias + eppnt->p_vaddr;
3192682674b8SRichard Henderson             vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
3193682674b8SRichard Henderson             vaddr_ps = TARGET_ELF_PAGESTART(vaddr);
319422d113b5SGiuseppe Musacchio 
319522d113b5SGiuseppe Musacchio             vaddr_ef = vaddr + eppnt->p_filesz;
319622d113b5SGiuseppe Musacchio             vaddr_em = vaddr + eppnt->p_memsz;
3197682674b8SRichard Henderson 
3198d87146bcSGiuseppe Musacchio             /*
319922d113b5SGiuseppe Musacchio              * Some segments may be completely empty, with a non-zero p_memsz
320022d113b5SGiuseppe Musacchio              * but no backing file segment.
3201d87146bcSGiuseppe Musacchio              */
3202d87146bcSGiuseppe Musacchio             if (eppnt->p_filesz != 0) {
320322d113b5SGiuseppe Musacchio                 vaddr_len = TARGET_ELF_PAGELENGTH(eppnt->p_filesz + vaddr_po);
3204d87146bcSGiuseppe Musacchio                 error = target_mmap(vaddr_ps, vaddr_len, elf_prot,
3205d87146bcSGiuseppe Musacchio                                     MAP_PRIVATE | MAP_FIXED,
32068e62a717SRichard Henderson                                     image_fd, eppnt->p_offset - vaddr_po);
3207d87146bcSGiuseppe Musacchio 
3208e89f07d3Spbrook                 if (error == -1) {
3209c7f17e7bSRichard Henderson                     goto exit_mmap;
321031e31b8aSbellard                 }
321131e31b8aSbellard 
321222d113b5SGiuseppe Musacchio                 /*
321322d113b5SGiuseppe Musacchio                  * If the load segment requests extra zeros (e.g. bss), map it.
321422d113b5SGiuseppe Musacchio                  */
321522d113b5SGiuseppe Musacchio                 if (eppnt->p_filesz < eppnt->p_memsz) {
3216682674b8SRichard Henderson                     zero_bss(vaddr_ef, vaddr_em, elf_prot);
3217682674b8SRichard Henderson                 }
321822d113b5SGiuseppe Musacchio             } else if (eppnt->p_memsz != 0) {
321922d113b5SGiuseppe Musacchio                 vaddr_len = TARGET_ELF_PAGELENGTH(eppnt->p_memsz + vaddr_po);
322022d113b5SGiuseppe Musacchio                 error = target_mmap(vaddr_ps, vaddr_len, elf_prot,
322122d113b5SGiuseppe Musacchio                                     MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
322222d113b5SGiuseppe Musacchio                                     -1, 0);
322322d113b5SGiuseppe Musacchio 
322422d113b5SGiuseppe Musacchio                 if (error == -1) {
322522d113b5SGiuseppe Musacchio                     goto exit_mmap;
322622d113b5SGiuseppe Musacchio                 }
322722d113b5SGiuseppe Musacchio             }
32288e62a717SRichard Henderson 
32298e62a717SRichard Henderson             /* Find the full program boundaries.  */
32308e62a717SRichard Henderson             if (elf_prot & PROT_EXEC) {
32318e62a717SRichard Henderson                 if (vaddr < info->start_code) {
32328e62a717SRichard Henderson                     info->start_code = vaddr;
3233cf129f3aSRichard Henderson                 }
32348e62a717SRichard Henderson                 if (vaddr_ef > info->end_code) {
32358e62a717SRichard Henderson                     info->end_code = vaddr_ef;
32368e62a717SRichard Henderson                 }
32378e62a717SRichard Henderson             }
32388e62a717SRichard Henderson             if (elf_prot & PROT_WRITE) {
32398e62a717SRichard Henderson                 if (vaddr < info->start_data) {
32408e62a717SRichard Henderson                     info->start_data = vaddr;
32418e62a717SRichard Henderson                 }
32428e62a717SRichard Henderson                 if (vaddr_ef > info->end_data) {
32438e62a717SRichard Henderson                     info->end_data = vaddr_ef;
32448e62a717SRichard Henderson                 }
32458a045188STimothy E Baldwin             }
32468e62a717SRichard Henderson             if (vaddr_em > info->brk) {
32478e62a717SRichard Henderson                 info->brk = vaddr_em;
32488e62a717SRichard Henderson             }
32495dd0db52SStefan Markovic #ifdef TARGET_MIPS
32505dd0db52SStefan Markovic         } else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
32515dd0db52SStefan Markovic             Mips_elf_abiflags_v0 abiflags;
32525dd0db52SStefan Markovic             if (eppnt->p_filesz < sizeof(Mips_elf_abiflags_v0)) {
3253c7f17e7bSRichard Henderson                 error_setg(&err, "Invalid PT_MIPS_ABIFLAGS entry");
32545dd0db52SStefan Markovic                 goto exit_errmsg;
32555dd0db52SStefan Markovic             }
32565dd0db52SStefan Markovic             if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
32575dd0db52SStefan Markovic                 memcpy(&abiflags, bprm_buf + eppnt->p_offset,
32585dd0db52SStefan Markovic                        sizeof(Mips_elf_abiflags_v0));
32595dd0db52SStefan Markovic             } else {
32605dd0db52SStefan Markovic                 retval = pread(image_fd, &abiflags, sizeof(Mips_elf_abiflags_v0),
32615dd0db52SStefan Markovic                                eppnt->p_offset);
32625dd0db52SStefan Markovic                 if (retval != sizeof(Mips_elf_abiflags_v0)) {
3263c7f17e7bSRichard Henderson                     goto exit_read;
32645dd0db52SStefan Markovic                 }
32655dd0db52SStefan Markovic             }
32665dd0db52SStefan Markovic             bswap_mips_abiflags(&abiflags);
3267c94cb6c9SStefan Markovic             info->fp_abi = abiflags.fp_abi;
32685dd0db52SStefan Markovic #endif
32698e62a717SRichard Henderson         }
32708e62a717SRichard Henderson     }
32718e62a717SRichard Henderson 
32728e62a717SRichard Henderson     if (info->end_data == 0) {
32738e62a717SRichard Henderson         info->start_data = info->end_code;
32748e62a717SRichard Henderson         info->end_data = info->end_code;
327531e31b8aSbellard     }
327631e31b8aSbellard 
3277682674b8SRichard Henderson     if (qemu_log_enabled()) {
32788e62a717SRichard Henderson         load_symbols(ehdr, image_fd, load_bias);
3279682674b8SRichard Henderson     }
328031e31b8aSbellard 
32817c10cb38SIlya Leoshkevich     debuginfo_report_elf(image_name, image_fd, load_bias);
32827c10cb38SIlya Leoshkevich 
328398c1076cSAlex Bennée     mmap_unlock();
328498c1076cSAlex Bennée 
32858e62a717SRichard Henderson     close(image_fd);
32868e62a717SRichard Henderson     return;
328731e31b8aSbellard 
32888e62a717SRichard Henderson  exit_read:
32898e62a717SRichard Henderson     if (retval >= 0) {
3290c7f17e7bSRichard Henderson         error_setg(&err, "Incomplete read of file header");
3291c7f17e7bSRichard Henderson     } else {
3292c7f17e7bSRichard Henderson         error_setg_errno(&err, errno, "Error reading file header");
32938e62a717SRichard Henderson     }
3294c7f17e7bSRichard Henderson     goto exit_errmsg;
3295c7f17e7bSRichard Henderson  exit_mmap:
3296c7f17e7bSRichard Henderson     error_setg_errno(&err, errno, "Error mapping file");
3297c7f17e7bSRichard Henderson     goto exit_errmsg;
32988e62a717SRichard Henderson  exit_errmsg:
3299c7f17e7bSRichard Henderson     error_reportf_err(err, "%s: ", image_name);
33008e62a717SRichard Henderson     exit(-1);
33018e62a717SRichard Henderson }
33028e62a717SRichard Henderson 
33038e62a717SRichard Henderson static void load_elf_interp(const char *filename, struct image_info *info,
33048e62a717SRichard Henderson                             char bprm_buf[BPRM_BUF_SIZE])
33058e62a717SRichard Henderson {
33068e62a717SRichard Henderson     int fd, retval;
3307808f6563SRichard Henderson     Error *err = NULL;
33088e62a717SRichard Henderson 
33098e62a717SRichard Henderson     fd = open(path(filename), O_RDONLY);
33108e62a717SRichard Henderson     if (fd < 0) {
3311808f6563SRichard Henderson         error_setg_file_open(&err, errno, filename);
3312808f6563SRichard Henderson         error_report_err(err);
3313808f6563SRichard Henderson         exit(-1);
33148e62a717SRichard Henderson     }
33158e62a717SRichard Henderson 
33168e62a717SRichard Henderson     retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
33178e62a717SRichard Henderson     if (retval < 0) {
3318808f6563SRichard Henderson         error_setg_errno(&err, errno, "Error reading file header");
3319808f6563SRichard Henderson         error_reportf_err(err, "%s: ", filename);
3320808f6563SRichard Henderson         exit(-1);
33218e62a717SRichard Henderson     }
3322808f6563SRichard Henderson 
33238e62a717SRichard Henderson     if (retval < BPRM_BUF_SIZE) {
33248e62a717SRichard Henderson         memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
33258e62a717SRichard Henderson     }
33268e62a717SRichard Henderson 
3327bf858897SRichard Henderson     load_elf_image(filename, fd, info, NULL, bprm_buf);
332831e31b8aSbellard }
332931e31b8aSbellard 
333049918a75Spbrook static int symfind(const void *s0, const void *s1)
333149918a75Spbrook {
3332c7c530cdSStefan Weil     target_ulong addr = *(target_ulong *)s0;
333349918a75Spbrook     struct elf_sym *sym = (struct elf_sym *)s1;
333449918a75Spbrook     int result = 0;
3335c7c530cdSStefan Weil     if (addr < sym->st_value) {
333649918a75Spbrook         result = -1;
3337c7c530cdSStefan Weil     } else if (addr >= sym->st_value + sym->st_size) {
333849918a75Spbrook         result = 1;
333949918a75Spbrook     }
334049918a75Spbrook     return result;
334149918a75Spbrook }
334249918a75Spbrook 
334349918a75Spbrook static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr)
334449918a75Spbrook {
334549918a75Spbrook #if ELF_CLASS == ELFCLASS32
334649918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf32;
334749918a75Spbrook #else
334849918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf64;
334949918a75Spbrook #endif
335049918a75Spbrook 
335149918a75Spbrook     // binary search
335249918a75Spbrook     struct elf_sym *sym;
335349918a75Spbrook 
3354c7c530cdSStefan Weil     sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
33557cba04f6SBlue Swirl     if (sym != NULL) {
335649918a75Spbrook         return s->disas_strtab + sym->st_name;
335749918a75Spbrook     }
335849918a75Spbrook 
335949918a75Spbrook     return "";
336049918a75Spbrook }
336149918a75Spbrook 
336249918a75Spbrook /* FIXME: This should use elf_ops.h  */
336349918a75Spbrook static int symcmp(const void *s0, const void *s1)
336449918a75Spbrook {
336549918a75Spbrook     struct elf_sym *sym0 = (struct elf_sym *)s0;
336649918a75Spbrook     struct elf_sym *sym1 = (struct elf_sym *)s1;
336749918a75Spbrook     return (sym0->st_value < sym1->st_value)
336849918a75Spbrook         ? -1
336949918a75Spbrook         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
337049918a75Spbrook }
337149918a75Spbrook 
3372689f936fSbellard /* Best attempt to load symbols from this ELF object. */
3373682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
3374689f936fSbellard {
3375682674b8SRichard Henderson     int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
33761e06262dSPeter Maydell     uint64_t segsz;
3377682674b8SRichard Henderson     struct elf_shdr *shdr;
3378b9475279SCédric VINCENT     char *strings = NULL;
3379b9475279SCédric VINCENT     struct syminfo *s = NULL;
3380b9475279SCédric VINCENT     struct elf_sym *new_syms, *syms = NULL;
338131e31b8aSbellard 
3382682674b8SRichard Henderson     shnum = hdr->e_shnum;
3383682674b8SRichard Henderson     i = shnum * sizeof(struct elf_shdr);
3384682674b8SRichard Henderson     shdr = (struct elf_shdr *)alloca(i);
3385682674b8SRichard Henderson     if (pread(fd, shdr, i, hdr->e_shoff) != i) {
3386689f936fSbellard         return;
3387682674b8SRichard Henderson     }
3388682674b8SRichard Henderson 
3389682674b8SRichard Henderson     bswap_shdr(shdr, shnum);
3390682674b8SRichard Henderson     for (i = 0; i < shnum; ++i) {
3391682674b8SRichard Henderson         if (shdr[i].sh_type == SHT_SYMTAB) {
3392682674b8SRichard Henderson             sym_idx = i;
3393682674b8SRichard Henderson             str_idx = shdr[i].sh_link;
3394689f936fSbellard             goto found;
3395689f936fSbellard         }
3396689f936fSbellard     }
3397682674b8SRichard Henderson 
3398682674b8SRichard Henderson     /* There will be no symbol table if the file was stripped.  */
3399682674b8SRichard Henderson     return;
3400689f936fSbellard 
3401689f936fSbellard  found:
3402689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them.  */
34030ef9ea29SPeter Maydell     s = g_try_new(struct syminfo, 1);
3404682674b8SRichard Henderson     if (!s) {
3405b9475279SCédric VINCENT         goto give_up;
3406682674b8SRichard Henderson     }
3407682674b8SRichard Henderson 
34081e06262dSPeter Maydell     segsz = shdr[str_idx].sh_size;
34091e06262dSPeter Maydell     s->disas_strtab = strings = g_try_malloc(segsz);
34101e06262dSPeter Maydell     if (!strings ||
34111e06262dSPeter Maydell         pread(fd, strings, segsz, shdr[str_idx].sh_offset) != segsz) {
3412b9475279SCédric VINCENT         goto give_up;
3413682674b8SRichard Henderson     }
3414689f936fSbellard 
34151e06262dSPeter Maydell     segsz = shdr[sym_idx].sh_size;
34161e06262dSPeter Maydell     syms = g_try_malloc(segsz);
34171e06262dSPeter Maydell     if (!syms || pread(fd, syms, segsz, shdr[sym_idx].sh_offset) != segsz) {
3418b9475279SCédric VINCENT         goto give_up;
3419682674b8SRichard Henderson     }
3420689f936fSbellard 
34211e06262dSPeter Maydell     if (segsz / sizeof(struct elf_sym) > INT_MAX) {
34221e06262dSPeter Maydell         /* Implausibly large symbol table: give up rather than ploughing
34231e06262dSPeter Maydell          * on with the number of symbols calculation overflowing
34241e06262dSPeter Maydell          */
34251e06262dSPeter Maydell         goto give_up;
34261e06262dSPeter Maydell     }
34271e06262dSPeter Maydell     nsyms = segsz / sizeof(struct elf_sym);
3428682674b8SRichard Henderson     for (i = 0; i < nsyms; ) {
342949918a75Spbrook         bswap_sym(syms + i);
3430682674b8SRichard Henderson         /* Throw away entries which we do not need.  */
3431682674b8SRichard Henderson         if (syms[i].st_shndx == SHN_UNDEF
3432682674b8SRichard Henderson             || syms[i].st_shndx >= SHN_LORESERVE
3433682674b8SRichard Henderson             || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
3434682674b8SRichard Henderson             if (i < --nsyms) {
343549918a75Spbrook                 syms[i] = syms[nsyms];
343649918a75Spbrook             }
3437682674b8SRichard Henderson         } else {
343849918a75Spbrook #if defined(TARGET_ARM) || defined (TARGET_MIPS)
343949918a75Spbrook             /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
344049918a75Spbrook             syms[i].st_value &= ~(target_ulong)1;
344149918a75Spbrook #endif
3442682674b8SRichard Henderson             syms[i].st_value += load_bias;
344349918a75Spbrook             i++;
344449918a75Spbrook         }
3445682674b8SRichard Henderson     }
344649918a75Spbrook 
3447b9475279SCédric VINCENT     /* No "useful" symbol.  */
3448b9475279SCédric VINCENT     if (nsyms == 0) {
3449b9475279SCédric VINCENT         goto give_up;
3450b9475279SCédric VINCENT     }
3451b9475279SCédric VINCENT 
34525d5c9930SRichard Henderson     /* Attempt to free the storage associated with the local symbols
34535d5c9930SRichard Henderson        that we threw away.  Whether or not this has any effect on the
34545d5c9930SRichard Henderson        memory allocation depends on the malloc implementation and how
34555d5c9930SRichard Henderson        many symbols we managed to discard.  */
34560ef9ea29SPeter Maydell     new_syms = g_try_renew(struct elf_sym, syms, nsyms);
34578d79de6eSStefan Weil     if (new_syms == NULL) {
3458b9475279SCédric VINCENT         goto give_up;
34595d5c9930SRichard Henderson     }
34608d79de6eSStefan Weil     syms = new_syms;
34615d5c9930SRichard Henderson 
346249918a75Spbrook     qsort(syms, nsyms, sizeof(*syms), symcmp);
346349918a75Spbrook 
346449918a75Spbrook     s->disas_num_syms = nsyms;
346549918a75Spbrook #if ELF_CLASS == ELFCLASS32
346649918a75Spbrook     s->disas_symtab.elf32 = syms;
346749918a75Spbrook #else
346849918a75Spbrook     s->disas_symtab.elf64 = syms;
346949918a75Spbrook #endif
3470682674b8SRichard Henderson     s->lookup_symbol = lookup_symbolxx;
3471e80cfcfcSbellard     s->next = syminfos;
3472e80cfcfcSbellard     syminfos = s;
3473b9475279SCédric VINCENT 
3474b9475279SCédric VINCENT     return;
3475b9475279SCédric VINCENT 
3476b9475279SCédric VINCENT give_up:
34770ef9ea29SPeter Maydell     g_free(s);
34780ef9ea29SPeter Maydell     g_free(strings);
34790ef9ea29SPeter Maydell     g_free(syms);
3480689f936fSbellard }
348131e31b8aSbellard 
3482768fe76eSYunQiang Su uint32_t get_elf_eflags(int fd)
3483768fe76eSYunQiang Su {
3484768fe76eSYunQiang Su     struct elfhdr ehdr;
3485768fe76eSYunQiang Su     off_t offset;
3486768fe76eSYunQiang Su     int ret;
3487768fe76eSYunQiang Su 
3488768fe76eSYunQiang Su     /* Read ELF header */
3489768fe76eSYunQiang Su     offset = lseek(fd, 0, SEEK_SET);
3490768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3491768fe76eSYunQiang Su         return 0;
3492768fe76eSYunQiang Su     }
3493768fe76eSYunQiang Su     ret = read(fd, &ehdr, sizeof(ehdr));
3494768fe76eSYunQiang Su     if (ret < sizeof(ehdr)) {
3495768fe76eSYunQiang Su         return 0;
3496768fe76eSYunQiang Su     }
3497768fe76eSYunQiang Su     offset = lseek(fd, offset, SEEK_SET);
3498768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3499768fe76eSYunQiang Su         return 0;
3500768fe76eSYunQiang Su     }
3501768fe76eSYunQiang Su 
3502768fe76eSYunQiang Su     /* Check ELF signature */
3503768fe76eSYunQiang Su     if (!elf_check_ident(&ehdr)) {
3504768fe76eSYunQiang Su         return 0;
3505768fe76eSYunQiang Su     }
3506768fe76eSYunQiang Su 
3507768fe76eSYunQiang Su     /* check header */
3508768fe76eSYunQiang Su     bswap_ehdr(&ehdr);
3509768fe76eSYunQiang Su     if (!elf_check_ehdr(&ehdr)) {
3510768fe76eSYunQiang Su         return 0;
3511768fe76eSYunQiang Su     }
3512768fe76eSYunQiang Su 
3513768fe76eSYunQiang Su     /* return architecture id */
3514768fe76eSYunQiang Su     return ehdr.e_flags;
3515768fe76eSYunQiang Su }
3516768fe76eSYunQiang Su 
3517f0116c54SWill Newton int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
351831e31b8aSbellard {
35198e62a717SRichard Henderson     struct image_info interp_info;
352031e31b8aSbellard     struct elfhdr elf_ex;
35218e62a717SRichard Henderson     char *elf_interpreter = NULL;
352259baae9aSStefan Brüns     char *scratch;
352331e31b8aSbellard 
3524abcac736SDaniel Santos     memset(&interp_info, 0, sizeof(interp_info));
3525abcac736SDaniel Santos #ifdef TARGET_MIPS
3526abcac736SDaniel Santos     interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
3527abcac736SDaniel Santos #endif
3528abcac736SDaniel Santos 
3529bf858897SRichard Henderson     info->start_mmap = (abi_ulong)ELF_START_MMAP;
353031e31b8aSbellard 
3531bf858897SRichard Henderson     load_elf_image(bprm->filename, bprm->fd, info,
3532bf858897SRichard Henderson                    &elf_interpreter, bprm->buf);
3533bf858897SRichard Henderson 
3534bf858897SRichard Henderson     /* ??? We need a copy of the elf header for passing to create_elf_tables.
3535bf858897SRichard Henderson        If we do nothing, we'll have overwritten this when we re-use bprm->buf
3536bf858897SRichard Henderson        when we load the interpreter.  */
3537bf858897SRichard Henderson     elf_ex = *(struct elfhdr *)bprm->buf;
353831e31b8aSbellard 
353959baae9aSStefan Brüns     /* Do this so that we can load the interpreter, if need be.  We will
354059baae9aSStefan Brüns        change some of these later */
354159baae9aSStefan Brüns     bprm->p = setup_arg_pages(bprm, info);
354259baae9aSStefan Brüns 
354359baae9aSStefan Brüns     scratch = g_new0(char, TARGET_PAGE_SIZE);
35447c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
354559baae9aSStefan Brüns         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
354659baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
35477c4ee5bcSRichard Henderson         info->file_string = bprm->p;
354859baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
354959baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
35507c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
355159baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
355259baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
35537c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
35547c4ee5bcSRichard Henderson     } else {
35557c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
35567c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
35577c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
35587c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
35597c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
35607c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
35617c4ee5bcSRichard Henderson         info->file_string = bprm->p;
35627c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
35637c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
35647c4ee5bcSRichard Henderson     }
35657c4ee5bcSRichard Henderson 
356659baae9aSStefan Brüns     g_free(scratch);
356759baae9aSStefan Brüns 
3568e5fe0c52Spbrook     if (!bprm->p) {
3569bf858897SRichard Henderson         fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
357031e31b8aSbellard         exit(-1);
35719955ffacSRichard Henderson     }
3572379f6698SPaul Brook 
35738e62a717SRichard Henderson     if (elf_interpreter) {
35748e62a717SRichard Henderson         load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
357531e31b8aSbellard 
35768e62a717SRichard Henderson         /* If the program interpreter is one of these two, then assume
35778e62a717SRichard Henderson            an iBCS2 image.  Otherwise assume a native linux image.  */
357831e31b8aSbellard 
35798e62a717SRichard Henderson         if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
35808e62a717SRichard Henderson             || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
35818e62a717SRichard Henderson             info->personality = PER_SVR4;
35828e62a717SRichard Henderson 
358331e31b8aSbellard             /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
35848e62a717SRichard Henderson                and some applications "depend" upon this behavior.  Since
35858e62a717SRichard Henderson                we do not have the power to recompile these, we emulate
35868e62a717SRichard Henderson                the SVr4 behavior.  Sigh.  */
35878e62a717SRichard Henderson             target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
358868754b44SPeter Maydell                         MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
358931e31b8aSbellard         }
3590c94cb6c9SStefan Markovic #ifdef TARGET_MIPS
3591c94cb6c9SStefan Markovic         info->interp_fp_abi = interp_info.fp_abi;
3592c94cb6c9SStefan Markovic #endif
35938e62a717SRichard Henderson     }
359431e31b8aSbellard 
3595db2af69dSRichard Henderson     /*
3596db2af69dSRichard Henderson      * TODO: load a vdso, which would also contain the signal trampolines.
3597db2af69dSRichard Henderson      * Otherwise, allocate a private page to hold them.
3598db2af69dSRichard Henderson      */
3599db2af69dSRichard Henderson     if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
3600802ae45eSLaurent Vivier         abi_long tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
3601db2af69dSRichard Henderson                                           PROT_READ | PROT_WRITE,
3602db2af69dSRichard Henderson                                           MAP_PRIVATE | MAP_ANON, -1, 0);
3603802ae45eSLaurent Vivier         if (tramp_page == -1) {
3604802ae45eSLaurent Vivier             return -errno;
3605802ae45eSLaurent Vivier         }
3606802ae45eSLaurent Vivier 
3607db2af69dSRichard Henderson         setup_sigtramp(tramp_page);
3608db2af69dSRichard Henderson         target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
3609db2af69dSRichard Henderson     }
3610db2af69dSRichard Henderson 
36118e62a717SRichard Henderson     bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
36128e62a717SRichard Henderson                                 info, (elf_interpreter ? &interp_info : NULL));
36138e62a717SRichard Henderson     info->start_stack = bprm->p;
36148e62a717SRichard Henderson 
36158e62a717SRichard Henderson     /* If we have an interpreter, set that as the program's entry point.
36168e78064eSRichard Henderson        Copy the load_bias as well, to help PPC64 interpret the entry
36178e62a717SRichard Henderson        point as a function descriptor.  Do this after creating elf tables
36188e62a717SRichard Henderson        so that we copy the original program entry point into the AUXV.  */
36198e62a717SRichard Henderson     if (elf_interpreter) {
36208e78064eSRichard Henderson         info->load_bias = interp_info.load_bias;
36218e62a717SRichard Henderson         info->entry = interp_info.entry;
36222b323087SPhilippe Mathieu-Daudé         g_free(elf_interpreter);
36238e62a717SRichard Henderson     }
362431e31b8aSbellard 
3625edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3626edf8e2afSMika Westerberg     bprm->core_dump = &elf_core_dump;
3627edf8e2afSMika Westerberg #endif
3628edf8e2afSMika Westerberg 
36296fd59449SRichard Henderson     /*
36306fd59449SRichard Henderson      * If we reserved extra space for brk, release it now.
36316fd59449SRichard Henderson      * The implementation of do_brk in syscalls.c expects to be able
36326fd59449SRichard Henderson      * to mmap pages in this space.
36336fd59449SRichard Henderson      */
36346fd59449SRichard Henderson     if (info->reserve_brk) {
36356fd59449SRichard Henderson         abi_ulong start_brk = HOST_PAGE_ALIGN(info->brk);
36366fd59449SRichard Henderson         abi_ulong end_brk = HOST_PAGE_ALIGN(info->brk + info->reserve_brk);
36376fd59449SRichard Henderson         target_munmap(start_brk, end_brk - start_brk);
36386fd59449SRichard Henderson     }
36396fd59449SRichard Henderson 
364031e31b8aSbellard     return 0;
364131e31b8aSbellard }
364231e31b8aSbellard 
3643edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3644edf8e2afSMika Westerberg /*
3645edf8e2afSMika Westerberg  * Definitions to generate Intel SVR4-like core files.
3646a2547a13SLaurent Desnogues  * These mostly have the same names as the SVR4 types with "target_elf_"
3647edf8e2afSMika Westerberg  * tacked on the front to prevent clashes with linux definitions,
3648edf8e2afSMika Westerberg  * and the typedef forms have been avoided.  This is mostly like
3649edf8e2afSMika Westerberg  * the SVR4 structure, but more Linuxy, with things that Linux does
3650edf8e2afSMika Westerberg  * not support and which gdb doesn't really use excluded.
3651edf8e2afSMika Westerberg  *
3652edf8e2afSMika Westerberg  * Fields we don't dump (their contents is zero) in linux-user qemu
3653edf8e2afSMika Westerberg  * are marked with XXX.
3654edf8e2afSMika Westerberg  *
3655edf8e2afSMika Westerberg  * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
3656edf8e2afSMika Westerberg  *
3657edf8e2afSMika Westerberg  * Porting ELF coredump for target is (quite) simple process.  First you
3658dd0a3651SNathan Froyd  * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
3659edf8e2afSMika Westerberg  * the target resides):
3660edf8e2afSMika Westerberg  *
3661edf8e2afSMika Westerberg  * #define USE_ELF_CORE_DUMP
3662edf8e2afSMika Westerberg  *
3663edf8e2afSMika Westerberg  * Next you define type of register set used for dumping.  ELF specification
3664edf8e2afSMika Westerberg  * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
3665edf8e2afSMika Westerberg  *
3666c227f099SAnthony Liguori  * typedef <target_regtype> target_elf_greg_t;
3667edf8e2afSMika Westerberg  * #define ELF_NREG <number of registers>
3668c227f099SAnthony Liguori  * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
3669edf8e2afSMika Westerberg  *
3670edf8e2afSMika Westerberg  * Last step is to implement target specific function that copies registers
3671edf8e2afSMika Westerberg  * from given cpu into just specified register set.  Prototype is:
3672edf8e2afSMika Westerberg  *
3673c227f099SAnthony Liguori  * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
36749349b4f9SAndreas Färber  *                                const CPUArchState *env);
3675edf8e2afSMika Westerberg  *
3676edf8e2afSMika Westerberg  * Parameters:
3677edf8e2afSMika Westerberg  *     regs - copy register values into here (allocated and zeroed by caller)
3678edf8e2afSMika Westerberg  *     env - copy registers from here
3679edf8e2afSMika Westerberg  *
3680edf8e2afSMika Westerberg  * Example for ARM target is provided in this file.
3681edf8e2afSMika Westerberg  */
3682edf8e2afSMika Westerberg 
3683edf8e2afSMika Westerberg /* An ELF note in memory */
3684edf8e2afSMika Westerberg struct memelfnote {
3685edf8e2afSMika Westerberg     const char *name;
3686edf8e2afSMika Westerberg     size_t     namesz;
3687edf8e2afSMika Westerberg     size_t     namesz_rounded;
3688edf8e2afSMika Westerberg     int        type;
3689edf8e2afSMika Westerberg     size_t     datasz;
369080f5ce75SLaurent Vivier     size_t     datasz_rounded;
3691edf8e2afSMika Westerberg     void       *data;
3692edf8e2afSMika Westerberg     size_t     notesz;
3693edf8e2afSMika Westerberg };
3694edf8e2afSMika Westerberg 
3695a2547a13SLaurent Desnogues struct target_elf_siginfo {
3696f8fd4fc4SPaolo Bonzini     abi_int    si_signo; /* signal number */
3697f8fd4fc4SPaolo Bonzini     abi_int    si_code;  /* extra code */
3698f8fd4fc4SPaolo Bonzini     abi_int    si_errno; /* errno */
3699edf8e2afSMika Westerberg };
3700edf8e2afSMika Westerberg 
3701a2547a13SLaurent Desnogues struct target_elf_prstatus {
3702a2547a13SLaurent Desnogues     struct target_elf_siginfo pr_info;      /* Info associated with signal */
37031ddd592fSPaolo Bonzini     abi_short          pr_cursig;    /* Current signal */
3704ca98ac83SPaolo Bonzini     abi_ulong          pr_sigpend;   /* XXX */
3705ca98ac83SPaolo Bonzini     abi_ulong          pr_sighold;   /* XXX */
3706c227f099SAnthony Liguori     target_pid_t       pr_pid;
3707c227f099SAnthony Liguori     target_pid_t       pr_ppid;
3708c227f099SAnthony Liguori     target_pid_t       pr_pgrp;
3709c227f099SAnthony Liguori     target_pid_t       pr_sid;
3710edf8e2afSMika Westerberg     struct target_timeval pr_utime;  /* XXX User time */
3711edf8e2afSMika Westerberg     struct target_timeval pr_stime;  /* XXX System time */
3712edf8e2afSMika Westerberg     struct target_timeval pr_cutime; /* XXX Cumulative user time */
3713edf8e2afSMika Westerberg     struct target_timeval pr_cstime; /* XXX Cumulative system time */
3714c227f099SAnthony Liguori     target_elf_gregset_t      pr_reg;       /* GP registers */
3715f8fd4fc4SPaolo Bonzini     abi_int            pr_fpvalid;   /* XXX */
3716edf8e2afSMika Westerberg };
3717edf8e2afSMika Westerberg 
3718edf8e2afSMika Westerberg #define ELF_PRARGSZ     (80) /* Number of chars for args */
3719edf8e2afSMika Westerberg 
3720a2547a13SLaurent Desnogues struct target_elf_prpsinfo {
3721edf8e2afSMika Westerberg     char         pr_state;       /* numeric process state */
3722edf8e2afSMika Westerberg     char         pr_sname;       /* char for pr_state */
3723edf8e2afSMika Westerberg     char         pr_zomb;        /* zombie */
3724edf8e2afSMika Westerberg     char         pr_nice;        /* nice val */
3725ca98ac83SPaolo Bonzini     abi_ulong    pr_flag;        /* flags */
3726c227f099SAnthony Liguori     target_uid_t pr_uid;
3727c227f099SAnthony Liguori     target_gid_t pr_gid;
3728c227f099SAnthony Liguori     target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
3729edf8e2afSMika Westerberg     /* Lots missing */
3730d7eb2b92SAlistair Francis     char    pr_fname[16] QEMU_NONSTRING; /* filename of executable */
3731edf8e2afSMika Westerberg     char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
3732edf8e2afSMika Westerberg };
3733edf8e2afSMika Westerberg 
3734edf8e2afSMika Westerberg /* Here is the structure in which status of each thread is captured. */
3735edf8e2afSMika Westerberg struct elf_thread_status {
373672cf2d4fSBlue Swirl     QTAILQ_ENTRY(elf_thread_status)  ets_link;
3737a2547a13SLaurent Desnogues     struct target_elf_prstatus prstatus;   /* NT_PRSTATUS */
3738edf8e2afSMika Westerberg #if 0
3739edf8e2afSMika Westerberg     elf_fpregset_t fpu;             /* NT_PRFPREG */
3740edf8e2afSMika Westerberg     struct task_struct *thread;
3741edf8e2afSMika Westerberg     elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
3742edf8e2afSMika Westerberg #endif
3743edf8e2afSMika Westerberg     struct memelfnote notes[1];
3744edf8e2afSMika Westerberg     int num_notes;
3745edf8e2afSMika Westerberg };
3746edf8e2afSMika Westerberg 
3747edf8e2afSMika Westerberg struct elf_note_info {
3748edf8e2afSMika Westerberg     struct memelfnote   *notes;
3749a2547a13SLaurent Desnogues     struct target_elf_prstatus *prstatus;  /* NT_PRSTATUS */
3750a2547a13SLaurent Desnogues     struct target_elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
3751edf8e2afSMika Westerberg 
3752b58deb34SPaolo Bonzini     QTAILQ_HEAD(, elf_thread_status) thread_list;
3753edf8e2afSMika Westerberg #if 0
3754edf8e2afSMika Westerberg     /*
3755edf8e2afSMika Westerberg      * Current version of ELF coredump doesn't support
3756edf8e2afSMika Westerberg      * dumping fp regs etc.
3757edf8e2afSMika Westerberg      */
3758edf8e2afSMika Westerberg     elf_fpregset_t *fpu;
3759edf8e2afSMika Westerberg     elf_fpxregset_t *xfpu;
3760edf8e2afSMika Westerberg     int thread_status_size;
3761edf8e2afSMika Westerberg #endif
3762edf8e2afSMika Westerberg     int notes_size;
3763edf8e2afSMika Westerberg     int numnote;
3764edf8e2afSMika Westerberg };
3765edf8e2afSMika Westerberg 
3766edf8e2afSMika Westerberg struct vm_area_struct {
37671a1c4db9SMikhail Ilyin     target_ulong   vma_start;  /* start vaddr of memory region */
37681a1c4db9SMikhail Ilyin     target_ulong   vma_end;    /* end vaddr of memory region */
3769edf8e2afSMika Westerberg     abi_ulong      vma_flags;  /* protection etc. flags for the region */
377072cf2d4fSBlue Swirl     QTAILQ_ENTRY(vm_area_struct) vma_link;
3771edf8e2afSMika Westerberg };
3772edf8e2afSMika Westerberg 
3773edf8e2afSMika Westerberg struct mm_struct {
377472cf2d4fSBlue Swirl     QTAILQ_HEAD(, vm_area_struct) mm_mmap;
3775edf8e2afSMika Westerberg     int mm_count;           /* number of mappings */
3776edf8e2afSMika Westerberg };
3777edf8e2afSMika Westerberg 
3778edf8e2afSMika Westerberg static struct mm_struct *vma_init(void);
3779edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *);
37801a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *, target_ulong,
37811a1c4db9SMikhail Ilyin                            target_ulong, abi_ulong);
3782edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *);
3783edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *);
3784edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *);
3785edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *);
37861a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
3787edf8e2afSMika Westerberg                       unsigned long flags);
3788edf8e2afSMika Westerberg 
3789edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
3790edf8e2afSMika Westerberg static void fill_note(struct memelfnote *, const char *, int,
3791edf8e2afSMika Westerberg                       unsigned int, void *);
3792a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
3793a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
3794edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *, const TaskState *);
3795edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
3796edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *);
3797edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *);
37989349b4f9SAndreas Färber static int fill_note_info(struct elf_note_info *, long, const CPUArchState *);
37999349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *, const CPUArchState *);
3800edf8e2afSMika Westerberg 
3801edf8e2afSMika Westerberg static int dump_write(int, const void *, size_t);
3802edf8e2afSMika Westerberg static int write_note(struct memelfnote *, int);
3803edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *, int);
3804edf8e2afSMika Westerberg 
3805edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
3806a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *prstatus)
3807edf8e2afSMika Westerberg {
3808ca98ac83SPaolo Bonzini     prstatus->pr_info.si_signo = tswap32(prstatus->pr_info.si_signo);
3809ca98ac83SPaolo Bonzini     prstatus->pr_info.si_code = tswap32(prstatus->pr_info.si_code);
3810ca98ac83SPaolo Bonzini     prstatus->pr_info.si_errno = tswap32(prstatus->pr_info.si_errno);
3811edf8e2afSMika Westerberg     prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
3812ca98ac83SPaolo Bonzini     prstatus->pr_sigpend = tswapal(prstatus->pr_sigpend);
3813ca98ac83SPaolo Bonzini     prstatus->pr_sighold = tswapal(prstatus->pr_sighold);
3814edf8e2afSMika Westerberg     prstatus->pr_pid = tswap32(prstatus->pr_pid);
3815edf8e2afSMika Westerberg     prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
3816edf8e2afSMika Westerberg     prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
3817edf8e2afSMika Westerberg     prstatus->pr_sid = tswap32(prstatus->pr_sid);
3818edf8e2afSMika Westerberg     /* cpu times are not filled, so we skip them */
3819edf8e2afSMika Westerberg     /* regs should be in correct format already */
3820edf8e2afSMika Westerberg     prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
3821edf8e2afSMika Westerberg }
3822edf8e2afSMika Westerberg 
3823a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
3824edf8e2afSMika Westerberg {
3825ca98ac83SPaolo Bonzini     psinfo->pr_flag = tswapal(psinfo->pr_flag);
3826edf8e2afSMika Westerberg     psinfo->pr_uid = tswap16(psinfo->pr_uid);
3827edf8e2afSMika Westerberg     psinfo->pr_gid = tswap16(psinfo->pr_gid);
3828edf8e2afSMika Westerberg     psinfo->pr_pid = tswap32(psinfo->pr_pid);
3829edf8e2afSMika Westerberg     psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
3830edf8e2afSMika Westerberg     psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
3831edf8e2afSMika Westerberg     psinfo->pr_sid = tswap32(psinfo->pr_sid);
3832edf8e2afSMika Westerberg }
3833991f8f0cSRichard Henderson 
3834991f8f0cSRichard Henderson static void bswap_note(struct elf_note *en)
3835991f8f0cSRichard Henderson {
3836991f8f0cSRichard Henderson     bswap32s(&en->n_namesz);
3837991f8f0cSRichard Henderson     bswap32s(&en->n_descsz);
3838991f8f0cSRichard Henderson     bswap32s(&en->n_type);
3839991f8f0cSRichard Henderson }
3840991f8f0cSRichard Henderson #else
3841991f8f0cSRichard Henderson static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
3842991f8f0cSRichard Henderson static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
3843991f8f0cSRichard Henderson static inline void bswap_note(struct elf_note *en) { }
3844edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
3845edf8e2afSMika Westerberg 
3846edf8e2afSMika Westerberg /*
3847edf8e2afSMika Westerberg  * Minimal support for linux memory regions.  These are needed
3848edf8e2afSMika Westerberg  * when we are finding out what memory exactly belongs to
3849edf8e2afSMika Westerberg  * emulated process.  No locks needed here, as long as
3850edf8e2afSMika Westerberg  * thread that received the signal is stopped.
3851edf8e2afSMika Westerberg  */
3852edf8e2afSMika Westerberg 
3853edf8e2afSMika Westerberg static struct mm_struct *vma_init(void)
3854edf8e2afSMika Westerberg {
3855edf8e2afSMika Westerberg     struct mm_struct *mm;
3856edf8e2afSMika Westerberg 
38577267c094SAnthony Liguori     if ((mm = g_malloc(sizeof (*mm))) == NULL)
3858edf8e2afSMika Westerberg         return (NULL);
3859edf8e2afSMika Westerberg 
3860edf8e2afSMika Westerberg     mm->mm_count = 0;
386172cf2d4fSBlue Swirl     QTAILQ_INIT(&mm->mm_mmap);
3862edf8e2afSMika Westerberg 
3863edf8e2afSMika Westerberg     return (mm);
3864edf8e2afSMika Westerberg }
3865edf8e2afSMika Westerberg 
3866edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *mm)
3867edf8e2afSMika Westerberg {
3868edf8e2afSMika Westerberg     struct vm_area_struct *vma;
3869edf8e2afSMika Westerberg 
3870edf8e2afSMika Westerberg     while ((vma = vma_first(mm)) != NULL) {
387172cf2d4fSBlue Swirl         QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
38727267c094SAnthony Liguori         g_free(vma);
3873edf8e2afSMika Westerberg     }
38747267c094SAnthony Liguori     g_free(mm);
3875edf8e2afSMika Westerberg }
3876edf8e2afSMika Westerberg 
38771a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *mm, target_ulong start,
38781a1c4db9SMikhail Ilyin                            target_ulong end, abi_ulong flags)
3879edf8e2afSMika Westerberg {
3880edf8e2afSMika Westerberg     struct vm_area_struct *vma;
3881edf8e2afSMika Westerberg 
38827267c094SAnthony Liguori     if ((vma = g_malloc0(sizeof (*vma))) == NULL)
3883edf8e2afSMika Westerberg         return (-1);
3884edf8e2afSMika Westerberg 
3885edf8e2afSMika Westerberg     vma->vma_start = start;
3886edf8e2afSMika Westerberg     vma->vma_end = end;
3887edf8e2afSMika Westerberg     vma->vma_flags = flags;
3888edf8e2afSMika Westerberg 
388972cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
3890edf8e2afSMika Westerberg     mm->mm_count++;
3891edf8e2afSMika Westerberg 
3892edf8e2afSMika Westerberg     return (0);
3893edf8e2afSMika Westerberg }
3894edf8e2afSMika Westerberg 
3895edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *mm)
3896edf8e2afSMika Westerberg {
389772cf2d4fSBlue Swirl     return (QTAILQ_FIRST(&mm->mm_mmap));
3898edf8e2afSMika Westerberg }
3899edf8e2afSMika Westerberg 
3900edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
3901edf8e2afSMika Westerberg {
390272cf2d4fSBlue Swirl     return (QTAILQ_NEXT(vma, vma_link));
3903edf8e2afSMika Westerberg }
3904edf8e2afSMika Westerberg 
3905edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *mm)
3906edf8e2afSMika Westerberg {
3907edf8e2afSMika Westerberg     return (mm->mm_count);
3908edf8e2afSMika Westerberg }
3909edf8e2afSMika Westerberg 
3910edf8e2afSMika Westerberg /*
3911edf8e2afSMika Westerberg  * Calculate file (dump) size of given memory region.
3912edf8e2afSMika Westerberg  */
3913edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
3914edf8e2afSMika Westerberg {
3915edf8e2afSMika Westerberg     /* if we cannot even read the first page, skip it */
3916c7169b02SRichard Henderson     if (!access_ok_untagged(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
3917edf8e2afSMika Westerberg         return (0);
3918edf8e2afSMika Westerberg 
3919edf8e2afSMika Westerberg     /*
3920edf8e2afSMika Westerberg      * Usually we don't dump executable pages as they contain
3921edf8e2afSMika Westerberg      * non-writable code that debugger can read directly from
3922edf8e2afSMika Westerberg      * target library etc.  However, thread stacks are marked
3923edf8e2afSMika Westerberg      * also executable so we read in first page of given region
3924edf8e2afSMika Westerberg      * and check whether it contains elf header.  If there is
3925edf8e2afSMika Westerberg      * no elf header, we dump it.
3926edf8e2afSMika Westerberg      */
3927edf8e2afSMika Westerberg     if (vma->vma_flags & PROT_EXEC) {
3928edf8e2afSMika Westerberg         char page[TARGET_PAGE_SIZE];
3929edf8e2afSMika Westerberg 
3930022625a8SPeter Maydell         if (copy_from_user(page, vma->vma_start, sizeof (page))) {
3931022625a8SPeter Maydell             return 0;
3932022625a8SPeter Maydell         }
3933edf8e2afSMika Westerberg         if ((page[EI_MAG0] == ELFMAG0) &&
3934edf8e2afSMika Westerberg             (page[EI_MAG1] == ELFMAG1) &&
3935edf8e2afSMika Westerberg             (page[EI_MAG2] == ELFMAG2) &&
3936edf8e2afSMika Westerberg             (page[EI_MAG3] == ELFMAG3)) {
3937edf8e2afSMika Westerberg             /*
3938edf8e2afSMika Westerberg              * Mappings are possibly from ELF binary.  Don't dump
3939edf8e2afSMika Westerberg              * them.
3940edf8e2afSMika Westerberg              */
3941edf8e2afSMika Westerberg             return (0);
3942edf8e2afSMika Westerberg         }
3943edf8e2afSMika Westerberg     }
3944edf8e2afSMika Westerberg 
3945edf8e2afSMika Westerberg     return (vma->vma_end - vma->vma_start);
3946edf8e2afSMika Westerberg }
3947edf8e2afSMika Westerberg 
39481a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
3949edf8e2afSMika Westerberg                       unsigned long flags)
3950edf8e2afSMika Westerberg {
3951edf8e2afSMika Westerberg     struct mm_struct *mm = (struct mm_struct *)priv;
3952edf8e2afSMika Westerberg 
3953edf8e2afSMika Westerberg     vma_add_mapping(mm, start, end, flags);
3954edf8e2afSMika Westerberg     return (0);
3955edf8e2afSMika Westerberg }
3956edf8e2afSMika Westerberg 
3957edf8e2afSMika Westerberg static void fill_note(struct memelfnote *note, const char *name, int type,
3958edf8e2afSMika Westerberg                       unsigned int sz, void *data)
3959edf8e2afSMika Westerberg {
3960edf8e2afSMika Westerberg     unsigned int namesz;
3961edf8e2afSMika Westerberg 
3962edf8e2afSMika Westerberg     namesz = strlen(name) + 1;
3963edf8e2afSMika Westerberg     note->name = name;
3964edf8e2afSMika Westerberg     note->namesz = namesz;
3965edf8e2afSMika Westerberg     note->namesz_rounded = roundup(namesz, sizeof (int32_t));
3966edf8e2afSMika Westerberg     note->type = type;
396780f5ce75SLaurent Vivier     note->datasz = sz;
396880f5ce75SLaurent Vivier     note->datasz_rounded = roundup(sz, sizeof (int32_t));
396980f5ce75SLaurent Vivier 
3970edf8e2afSMika Westerberg     note->data = data;
3971edf8e2afSMika Westerberg 
3972edf8e2afSMika Westerberg     /*
3973edf8e2afSMika Westerberg      * We calculate rounded up note size here as specified by
3974edf8e2afSMika Westerberg      * ELF document.
3975edf8e2afSMika Westerberg      */
3976edf8e2afSMika Westerberg     note->notesz = sizeof (struct elf_note) +
397780f5ce75SLaurent Vivier         note->namesz_rounded + note->datasz_rounded;
3978edf8e2afSMika Westerberg }
3979edf8e2afSMika Westerberg 
3980edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
3981edf8e2afSMika Westerberg                             uint32_t flags)
3982edf8e2afSMika Westerberg {
3983edf8e2afSMika Westerberg     (void) memset(elf, 0, sizeof(*elf));
3984edf8e2afSMika Westerberg 
3985edf8e2afSMika Westerberg     (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
3986edf8e2afSMika Westerberg     elf->e_ident[EI_CLASS] = ELF_CLASS;
3987edf8e2afSMika Westerberg     elf->e_ident[EI_DATA] = ELF_DATA;
3988edf8e2afSMika Westerberg     elf->e_ident[EI_VERSION] = EV_CURRENT;
3989edf8e2afSMika Westerberg     elf->e_ident[EI_OSABI] = ELF_OSABI;
3990edf8e2afSMika Westerberg 
3991edf8e2afSMika Westerberg     elf->e_type = ET_CORE;
3992edf8e2afSMika Westerberg     elf->e_machine = machine;
3993edf8e2afSMika Westerberg     elf->e_version = EV_CURRENT;
3994edf8e2afSMika Westerberg     elf->e_phoff = sizeof(struct elfhdr);
3995edf8e2afSMika Westerberg     elf->e_flags = flags;
3996edf8e2afSMika Westerberg     elf->e_ehsize = sizeof(struct elfhdr);
3997edf8e2afSMika Westerberg     elf->e_phentsize = sizeof(struct elf_phdr);
3998edf8e2afSMika Westerberg     elf->e_phnum = segs;
3999edf8e2afSMika Westerberg 
4000edf8e2afSMika Westerberg     bswap_ehdr(elf);
4001edf8e2afSMika Westerberg }
4002edf8e2afSMika Westerberg 
4003edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
4004edf8e2afSMika Westerberg {
4005edf8e2afSMika Westerberg     phdr->p_type = PT_NOTE;
4006edf8e2afSMika Westerberg     phdr->p_offset = offset;
4007edf8e2afSMika Westerberg     phdr->p_vaddr = 0;
4008edf8e2afSMika Westerberg     phdr->p_paddr = 0;
4009edf8e2afSMika Westerberg     phdr->p_filesz = sz;
4010edf8e2afSMika Westerberg     phdr->p_memsz = 0;
4011edf8e2afSMika Westerberg     phdr->p_flags = 0;
4012edf8e2afSMika Westerberg     phdr->p_align = 0;
4013edf8e2afSMika Westerberg 
4014991f8f0cSRichard Henderson     bswap_phdr(phdr, 1);
4015edf8e2afSMika Westerberg }
4016edf8e2afSMika Westerberg 
4017edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *note)
4018edf8e2afSMika Westerberg {
4019edf8e2afSMika Westerberg     return (note->notesz);
4020edf8e2afSMika Westerberg }
4021edf8e2afSMika Westerberg 
4022a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *prstatus,
4023edf8e2afSMika Westerberg                           const TaskState *ts, int signr)
4024edf8e2afSMika Westerberg {
4025edf8e2afSMika Westerberg     (void) memset(prstatus, 0, sizeof (*prstatus));
4026edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
4027edf8e2afSMika Westerberg     prstatus->pr_pid = ts->ts_tid;
4028edf8e2afSMika Westerberg     prstatus->pr_ppid = getppid();
4029edf8e2afSMika Westerberg     prstatus->pr_pgrp = getpgrp();
4030edf8e2afSMika Westerberg     prstatus->pr_sid = getsid(0);
4031edf8e2afSMika Westerberg 
4032edf8e2afSMika Westerberg     bswap_prstatus(prstatus);
4033edf8e2afSMika Westerberg }
4034edf8e2afSMika Westerberg 
4035a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
4036edf8e2afSMika Westerberg {
4037900cfbcaSJim Meyering     char *base_filename;
4038edf8e2afSMika Westerberg     unsigned int i, len;
4039edf8e2afSMika Westerberg 
4040edf8e2afSMika Westerberg     (void) memset(psinfo, 0, sizeof (*psinfo));
4041edf8e2afSMika Westerberg 
40425f779a3aSIlya Leoshkevich     len = ts->info->env_strings - ts->info->arg_strings;
4043edf8e2afSMika Westerberg     if (len >= ELF_PRARGSZ)
4044edf8e2afSMika Westerberg         len = ELF_PRARGSZ - 1;
40455f779a3aSIlya Leoshkevich     if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_strings, len)) {
4046edf8e2afSMika Westerberg         return -EFAULT;
40475f779a3aSIlya Leoshkevich     }
4048edf8e2afSMika Westerberg     for (i = 0; i < len; i++)
4049edf8e2afSMika Westerberg         if (psinfo->pr_psargs[i] == 0)
4050edf8e2afSMika Westerberg             psinfo->pr_psargs[i] = ' ';
4051edf8e2afSMika Westerberg     psinfo->pr_psargs[len] = 0;
4052edf8e2afSMika Westerberg 
4053edf8e2afSMika Westerberg     psinfo->pr_pid = getpid();
4054edf8e2afSMika Westerberg     psinfo->pr_ppid = getppid();
4055edf8e2afSMika Westerberg     psinfo->pr_pgrp = getpgrp();
4056edf8e2afSMika Westerberg     psinfo->pr_sid = getsid(0);
4057edf8e2afSMika Westerberg     psinfo->pr_uid = getuid();
4058edf8e2afSMika Westerberg     psinfo->pr_gid = getgid();
4059edf8e2afSMika Westerberg 
4060900cfbcaSJim Meyering     base_filename = g_path_get_basename(ts->bprm->filename);
4061900cfbcaSJim Meyering     /*
4062900cfbcaSJim Meyering      * Using strncpy here is fine: at max-length,
4063900cfbcaSJim Meyering      * this field is not NUL-terminated.
4064900cfbcaSJim Meyering      */
4065edf8e2afSMika Westerberg     (void) strncpy(psinfo->pr_fname, base_filename,
4066edf8e2afSMika Westerberg                    sizeof(psinfo->pr_fname));
4067edf8e2afSMika Westerberg 
4068900cfbcaSJim Meyering     g_free(base_filename);
4069edf8e2afSMika Westerberg     bswap_psinfo(psinfo);
4070edf8e2afSMika Westerberg     return (0);
4071edf8e2afSMika Westerberg }
4072edf8e2afSMika Westerberg 
4073edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
4074edf8e2afSMika Westerberg {
4075edf8e2afSMika Westerberg     elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
4076edf8e2afSMika Westerberg     elf_addr_t orig_auxv = auxv;
4077edf8e2afSMika Westerberg     void *ptr;
4078125b0f55SAlexander Graf     int len = ts->info->auxv_len;
4079edf8e2afSMika Westerberg 
4080edf8e2afSMika Westerberg     /*
4081edf8e2afSMika Westerberg      * Auxiliary vector is stored in target process stack.  It contains
4082edf8e2afSMika Westerberg      * {type, value} pairs that we need to dump into note.  This is not
4083edf8e2afSMika Westerberg      * strictly necessary but we do it here for sake of completeness.
4084edf8e2afSMika Westerberg      */
4085edf8e2afSMika Westerberg 
4086edf8e2afSMika Westerberg     /* read in whole auxv vector and copy it to memelfnote */
4087edf8e2afSMika Westerberg     ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
4088edf8e2afSMika Westerberg     if (ptr != NULL) {
4089edf8e2afSMika Westerberg         fill_note(note, "CORE", NT_AUXV, len, ptr);
4090edf8e2afSMika Westerberg         unlock_user(ptr, auxv, len);
4091edf8e2afSMika Westerberg     }
4092edf8e2afSMika Westerberg }
4093edf8e2afSMika Westerberg 
4094edf8e2afSMika Westerberg /*
4095edf8e2afSMika Westerberg  * Constructs name of coredump file.  We have following convention
4096edf8e2afSMika Westerberg  * for the name:
4097edf8e2afSMika Westerberg  *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
4098edf8e2afSMika Westerberg  *
409968af19adSDaniel P. Berrangé  * Returns the filename
4100edf8e2afSMika Westerberg  */
410168af19adSDaniel P. Berrangé static char *core_dump_filename(const TaskState *ts)
4102edf8e2afSMika Westerberg {
410368af19adSDaniel P. Berrangé     g_autoptr(GDateTime) now = g_date_time_new_now_local();
410468af19adSDaniel P. Berrangé     g_autofree char *nowstr = g_date_time_format(now, "%Y%m%d-%H%M%S");
410568af19adSDaniel P. Berrangé     g_autofree char *base_filename = g_path_get_basename(ts->bprm->filename);
4106edf8e2afSMika Westerberg 
410768af19adSDaniel P. Berrangé     return g_strdup_printf("qemu_%s_%s_%d.core",
410868af19adSDaniel P. Berrangé                            base_filename, nowstr, (int)getpid());
4109edf8e2afSMika Westerberg }
4110edf8e2afSMika Westerberg 
4111edf8e2afSMika Westerberg static int dump_write(int fd, const void *ptr, size_t size)
4112edf8e2afSMika Westerberg {
4113edf8e2afSMika Westerberg     const char *bufp = (const char *)ptr;
4114edf8e2afSMika Westerberg     ssize_t bytes_written, bytes_left;
4115edf8e2afSMika Westerberg     struct rlimit dumpsize;
4116edf8e2afSMika Westerberg     off_t pos;
4117edf8e2afSMika Westerberg 
4118edf8e2afSMika Westerberg     bytes_written = 0;
4119edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
4120edf8e2afSMika Westerberg     if ((pos = lseek(fd, 0, SEEK_CUR))==-1) {
4121edf8e2afSMika Westerberg         if (errno == ESPIPE) { /* not a seekable stream */
4122edf8e2afSMika Westerberg             bytes_left = size;
4123edf8e2afSMika Westerberg         } else {
4124edf8e2afSMika Westerberg             return pos;
4125edf8e2afSMika Westerberg         }
4126edf8e2afSMika Westerberg     } else {
4127edf8e2afSMika Westerberg         if (dumpsize.rlim_cur <= pos) {
4128edf8e2afSMika Westerberg             return -1;
4129edf8e2afSMika Westerberg         } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
4130edf8e2afSMika Westerberg             bytes_left = size;
4131edf8e2afSMika Westerberg         } else {
4132edf8e2afSMika Westerberg             size_t limit_left=dumpsize.rlim_cur - pos;
4133edf8e2afSMika Westerberg             bytes_left = limit_left >= size ? size : limit_left ;
4134edf8e2afSMika Westerberg         }
4135edf8e2afSMika Westerberg     }
4136edf8e2afSMika Westerberg 
4137edf8e2afSMika Westerberg     /*
4138edf8e2afSMika Westerberg      * In normal conditions, single write(2) should do but
4139edf8e2afSMika Westerberg      * in case of socket etc. this mechanism is more portable.
4140edf8e2afSMika Westerberg      */
4141edf8e2afSMika Westerberg     do {
4142edf8e2afSMika Westerberg         bytes_written = write(fd, bufp, bytes_left);
4143edf8e2afSMika Westerberg         if (bytes_written < 0) {
4144edf8e2afSMika Westerberg             if (errno == EINTR)
4145edf8e2afSMika Westerberg                 continue;
4146edf8e2afSMika Westerberg             return (-1);
4147edf8e2afSMika Westerberg         } else if (bytes_written == 0) { /* eof */
4148edf8e2afSMika Westerberg             return (-1);
4149edf8e2afSMika Westerberg         }
4150edf8e2afSMika Westerberg         bufp += bytes_written;
4151edf8e2afSMika Westerberg         bytes_left -= bytes_written;
4152edf8e2afSMika Westerberg     } while (bytes_left > 0);
4153edf8e2afSMika Westerberg 
4154edf8e2afSMika Westerberg     return (0);
4155edf8e2afSMika Westerberg }
4156edf8e2afSMika Westerberg 
4157edf8e2afSMika Westerberg static int write_note(struct memelfnote *men, int fd)
4158edf8e2afSMika Westerberg {
4159edf8e2afSMika Westerberg     struct elf_note en;
4160edf8e2afSMika Westerberg 
4161edf8e2afSMika Westerberg     en.n_namesz = men->namesz;
4162edf8e2afSMika Westerberg     en.n_type = men->type;
4163edf8e2afSMika Westerberg     en.n_descsz = men->datasz;
4164edf8e2afSMika Westerberg 
4165edf8e2afSMika Westerberg     bswap_note(&en);
4166edf8e2afSMika Westerberg 
4167edf8e2afSMika Westerberg     if (dump_write(fd, &en, sizeof(en)) != 0)
4168edf8e2afSMika Westerberg         return (-1);
4169edf8e2afSMika Westerberg     if (dump_write(fd, men->name, men->namesz_rounded) != 0)
4170edf8e2afSMika Westerberg         return (-1);
417180f5ce75SLaurent Vivier     if (dump_write(fd, men->data, men->datasz_rounded) != 0)
4172edf8e2afSMika Westerberg         return (-1);
4173edf8e2afSMika Westerberg 
4174edf8e2afSMika Westerberg     return (0);
4175edf8e2afSMika Westerberg }
4176edf8e2afSMika Westerberg 
41779349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *info, const CPUArchState *env)
4178edf8e2afSMika Westerberg {
417929a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
41800429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4181edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4182edf8e2afSMika Westerberg 
41837267c094SAnthony Liguori     ets = g_malloc0(sizeof (*ets));
4184edf8e2afSMika Westerberg     ets->num_notes = 1; /* only prstatus is dumped */
4185edf8e2afSMika Westerberg     fill_prstatus(&ets->prstatus, ts, 0);
4186edf8e2afSMika Westerberg     elf_core_copy_regs(&ets->prstatus.pr_reg, env);
4187edf8e2afSMika Westerberg     fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
4188edf8e2afSMika Westerberg               &ets->prstatus);
4189edf8e2afSMika Westerberg 
419072cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
4191edf8e2afSMika Westerberg 
4192edf8e2afSMika Westerberg     info->notes_size += note_size(&ets->notes[0]);
4193edf8e2afSMika Westerberg }
4194edf8e2afSMika Westerberg 
41956afafa86SPeter Maydell static void init_note_info(struct elf_note_info *info)
41966afafa86SPeter Maydell {
41976afafa86SPeter Maydell     /* Initialize the elf_note_info structure so that it is at
41986afafa86SPeter Maydell      * least safe to call free_note_info() on it. Must be
41996afafa86SPeter Maydell      * called before calling fill_note_info().
42006afafa86SPeter Maydell      */
42016afafa86SPeter Maydell     memset(info, 0, sizeof (*info));
42026afafa86SPeter Maydell     QTAILQ_INIT(&info->thread_list);
42036afafa86SPeter Maydell }
42046afafa86SPeter Maydell 
4205edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *info,
42069349b4f9SAndreas Färber                           long signr, const CPUArchState *env)
4207edf8e2afSMika Westerberg {
4208edf8e2afSMika Westerberg #define NUMNOTES 3
420929a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
42100429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4211edf8e2afSMika Westerberg     int i;
4212edf8e2afSMika Westerberg 
4213c78d65e8SMarkus Armbruster     info->notes = g_new0(struct memelfnote, NUMNOTES);
4214edf8e2afSMika Westerberg     if (info->notes == NULL)
4215edf8e2afSMika Westerberg         return (-ENOMEM);
42167267c094SAnthony Liguori     info->prstatus = g_malloc0(sizeof (*info->prstatus));
4217edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4218edf8e2afSMika Westerberg         return (-ENOMEM);
42197267c094SAnthony Liguori     info->psinfo = g_malloc0(sizeof (*info->psinfo));
4220edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4221edf8e2afSMika Westerberg         return (-ENOMEM);
4222edf8e2afSMika Westerberg 
4223edf8e2afSMika Westerberg     /*
4224edf8e2afSMika Westerberg      * First fill in status (and registers) of current thread
4225edf8e2afSMika Westerberg      * including process info & aux vector.
4226edf8e2afSMika Westerberg      */
4227edf8e2afSMika Westerberg     fill_prstatus(info->prstatus, ts, signr);
4228edf8e2afSMika Westerberg     elf_core_copy_regs(&info->prstatus->pr_reg, env);
4229edf8e2afSMika Westerberg     fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
4230edf8e2afSMika Westerberg               sizeof (*info->prstatus), info->prstatus);
4231edf8e2afSMika Westerberg     fill_psinfo(info->psinfo, ts);
4232edf8e2afSMika Westerberg     fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
4233edf8e2afSMika Westerberg               sizeof (*info->psinfo), info->psinfo);
4234edf8e2afSMika Westerberg     fill_auxv_note(&info->notes[2], ts);
4235edf8e2afSMika Westerberg     info->numnote = 3;
4236edf8e2afSMika Westerberg 
4237edf8e2afSMika Westerberg     info->notes_size = 0;
4238edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4239edf8e2afSMika Westerberg         info->notes_size += note_size(&info->notes[i]);
4240edf8e2afSMika Westerberg 
4241edf8e2afSMika Westerberg     /* read and fill status of all threads */
4242edf8e2afSMika Westerberg     cpu_list_lock();
4243bdc44640SAndreas Färber     CPU_FOREACH(cpu) {
4244a2247f8eSAndreas Färber         if (cpu == thread_cpu) {
4245edf8e2afSMika Westerberg             continue;
4246182735efSAndreas Färber         }
42472f6f4290SPhilippe Mathieu-Daudé         fill_thread_info(info, cpu->env_ptr);
4248edf8e2afSMika Westerberg     }
4249edf8e2afSMika Westerberg     cpu_list_unlock();
4250edf8e2afSMika Westerberg 
4251edf8e2afSMika Westerberg     return (0);
4252edf8e2afSMika Westerberg }
4253edf8e2afSMika Westerberg 
4254edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *info)
4255edf8e2afSMika Westerberg {
4256edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4257edf8e2afSMika Westerberg 
425872cf2d4fSBlue Swirl     while (!QTAILQ_EMPTY(&info->thread_list)) {
425972cf2d4fSBlue Swirl         ets = QTAILQ_FIRST(&info->thread_list);
426072cf2d4fSBlue Swirl         QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
42617267c094SAnthony Liguori         g_free(ets);
4262edf8e2afSMika Westerberg     }
4263edf8e2afSMika Westerberg 
42647267c094SAnthony Liguori     g_free(info->prstatus);
42657267c094SAnthony Liguori     g_free(info->psinfo);
42667267c094SAnthony Liguori     g_free(info->notes);
4267edf8e2afSMika Westerberg }
4268edf8e2afSMika Westerberg 
4269edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *info, int fd)
4270edf8e2afSMika Westerberg {
4271edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4272edf8e2afSMika Westerberg     int i, error = 0;
4273edf8e2afSMika Westerberg 
4274edf8e2afSMika Westerberg     /* write prstatus, psinfo and auxv for current thread */
4275edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4276edf8e2afSMika Westerberg         if ((error = write_note(&info->notes[i], fd)) != 0)
4277edf8e2afSMika Westerberg             return (error);
4278edf8e2afSMika Westerberg 
4279edf8e2afSMika Westerberg     /* write prstatus for each thread */
428052a53afeSEmilio G. Cota     QTAILQ_FOREACH(ets, &info->thread_list, ets_link) {
4281edf8e2afSMika Westerberg         if ((error = write_note(&ets->notes[0], fd)) != 0)
4282edf8e2afSMika Westerberg             return (error);
4283edf8e2afSMika Westerberg     }
4284edf8e2afSMika Westerberg 
4285edf8e2afSMika Westerberg     return (0);
4286edf8e2afSMika Westerberg }
4287edf8e2afSMika Westerberg 
4288edf8e2afSMika Westerberg /*
4289edf8e2afSMika Westerberg  * Write out ELF coredump.
4290edf8e2afSMika Westerberg  *
4291edf8e2afSMika Westerberg  * See documentation of ELF object file format in:
4292edf8e2afSMika Westerberg  * http://www.caldera.com/developers/devspecs/gabi41.pdf
4293edf8e2afSMika Westerberg  *
4294edf8e2afSMika Westerberg  * Coredump format in linux is following:
4295edf8e2afSMika Westerberg  *
4296edf8e2afSMika Westerberg  * 0   +----------------------+         \
4297edf8e2afSMika Westerberg  *     | ELF header           | ET_CORE  |
4298edf8e2afSMika Westerberg  *     +----------------------+          |
4299edf8e2afSMika Westerberg  *     | ELF program headers  |          |--- headers
4300edf8e2afSMika Westerberg  *     | - NOTE section       |          |
4301edf8e2afSMika Westerberg  *     | - PT_LOAD sections   |          |
4302edf8e2afSMika Westerberg  *     +----------------------+         /
4303edf8e2afSMika Westerberg  *     | NOTEs:               |
4304edf8e2afSMika Westerberg  *     | - NT_PRSTATUS        |
4305edf8e2afSMika Westerberg  *     | - NT_PRSINFO         |
4306edf8e2afSMika Westerberg  *     | - NT_AUXV            |
4307edf8e2afSMika Westerberg  *     +----------------------+ <-- aligned to target page
4308edf8e2afSMika Westerberg  *     | Process memory dump  |
4309edf8e2afSMika Westerberg  *     :                      :
4310edf8e2afSMika Westerberg  *     .                      .
4311edf8e2afSMika Westerberg  *     :                      :
4312edf8e2afSMika Westerberg  *     |                      |
4313edf8e2afSMika Westerberg  *     +----------------------+
4314edf8e2afSMika Westerberg  *
4315edf8e2afSMika Westerberg  * NT_PRSTATUS -> struct elf_prstatus (per thread)
4316edf8e2afSMika Westerberg  * NT_PRSINFO  -> struct elf_prpsinfo
4317edf8e2afSMika Westerberg  * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
4318edf8e2afSMika Westerberg  *
4319edf8e2afSMika Westerberg  * Format follows System V format as close as possible.  Current
4320edf8e2afSMika Westerberg  * version limitations are as follows:
4321edf8e2afSMika Westerberg  *     - no floating point registers are dumped
4322edf8e2afSMika Westerberg  *
4323edf8e2afSMika Westerberg  * Function returns 0 in case of success, negative errno otherwise.
4324edf8e2afSMika Westerberg  *
4325edf8e2afSMika Westerberg  * TODO: make this work also during runtime: it should be
4326edf8e2afSMika Westerberg  * possible to force coredump from running process and then
4327edf8e2afSMika Westerberg  * continue processing.  For example qemu could set up SIGUSR2
4328edf8e2afSMika Westerberg  * handler (provided that target process haven't registered
4329edf8e2afSMika Westerberg  * handler for that) that does the dump when signal is received.
4330edf8e2afSMika Westerberg  */
43319349b4f9SAndreas Färber static int elf_core_dump(int signr, const CPUArchState *env)
4332edf8e2afSMika Westerberg {
433329a0af61SRichard Henderson     const CPUState *cpu = env_cpu((CPUArchState *)env);
43340429a971SAndreas Färber     const TaskState *ts = (const TaskState *)cpu->opaque;
4335edf8e2afSMika Westerberg     struct vm_area_struct *vma = NULL;
433668af19adSDaniel P. Berrangé     g_autofree char *corefile = NULL;
4337edf8e2afSMika Westerberg     struct elf_note_info info;
4338edf8e2afSMika Westerberg     struct elfhdr elf;
4339edf8e2afSMika Westerberg     struct elf_phdr phdr;
4340edf8e2afSMika Westerberg     struct rlimit dumpsize;
4341edf8e2afSMika Westerberg     struct mm_struct *mm = NULL;
4342edf8e2afSMika Westerberg     off_t offset = 0, data_offset = 0;
4343edf8e2afSMika Westerberg     int segs = 0;
4344edf8e2afSMika Westerberg     int fd = -1;
4345edf8e2afSMika Westerberg 
43466afafa86SPeter Maydell     init_note_info(&info);
43476afafa86SPeter Maydell 
4348edf8e2afSMika Westerberg     errno = 0;
4349edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
4350edf8e2afSMika Westerberg     if (dumpsize.rlim_cur == 0)
4351edf8e2afSMika Westerberg         return 0;
4352edf8e2afSMika Westerberg 
435368af19adSDaniel P. Berrangé     corefile = core_dump_filename(ts);
4354edf8e2afSMika Westerberg 
4355edf8e2afSMika Westerberg     if ((fd = open(corefile, O_WRONLY | O_CREAT,
4356edf8e2afSMika Westerberg                    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
4357edf8e2afSMika Westerberg         return (-errno);
4358edf8e2afSMika Westerberg 
4359edf8e2afSMika Westerberg     /*
4360edf8e2afSMika Westerberg      * Walk through target process memory mappings and
4361edf8e2afSMika Westerberg      * set up structure containing this information.  After
4362edf8e2afSMika Westerberg      * this point vma_xxx functions can be used.
4363edf8e2afSMika Westerberg      */
4364edf8e2afSMika Westerberg     if ((mm = vma_init()) == NULL)
4365edf8e2afSMika Westerberg         goto out;
4366edf8e2afSMika Westerberg 
4367edf8e2afSMika Westerberg     walk_memory_regions(mm, vma_walker);
4368edf8e2afSMika Westerberg     segs = vma_get_mapping_count(mm);
4369edf8e2afSMika Westerberg 
4370edf8e2afSMika Westerberg     /*
4371edf8e2afSMika Westerberg      * Construct valid coredump ELF header.  We also
4372edf8e2afSMika Westerberg      * add one more segment for notes.
4373edf8e2afSMika Westerberg      */
4374edf8e2afSMika Westerberg     fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
4375edf8e2afSMika Westerberg     if (dump_write(fd, &elf, sizeof (elf)) != 0)
4376edf8e2afSMika Westerberg         goto out;
4377edf8e2afSMika Westerberg 
4378b6af0975SDaniel P. Berrange     /* fill in the in-memory version of notes */
4379edf8e2afSMika Westerberg     if (fill_note_info(&info, signr, env) < 0)
4380edf8e2afSMika Westerberg         goto out;
4381edf8e2afSMika Westerberg 
4382edf8e2afSMika Westerberg     offset += sizeof (elf);                             /* elf header */
4383edf8e2afSMika Westerberg     offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
4384edf8e2afSMika Westerberg 
4385edf8e2afSMika Westerberg     /* write out notes program header */
4386edf8e2afSMika Westerberg     fill_elf_note_phdr(&phdr, info.notes_size, offset);
4387edf8e2afSMika Westerberg 
4388edf8e2afSMika Westerberg     offset += info.notes_size;
4389edf8e2afSMika Westerberg     if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
4390edf8e2afSMika Westerberg         goto out;
4391edf8e2afSMika Westerberg 
4392edf8e2afSMika Westerberg     /*
4393edf8e2afSMika Westerberg      * ELF specification wants data to start at page boundary so
4394edf8e2afSMika Westerberg      * we align it here.
4395edf8e2afSMika Westerberg      */
439680f5ce75SLaurent Vivier     data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
4397edf8e2afSMika Westerberg 
4398edf8e2afSMika Westerberg     /*
4399edf8e2afSMika Westerberg      * Write program headers for memory regions mapped in
4400edf8e2afSMika Westerberg      * the target process.
4401edf8e2afSMika Westerberg      */
4402edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4403edf8e2afSMika Westerberg         (void) memset(&phdr, 0, sizeof (phdr));
4404edf8e2afSMika Westerberg 
4405edf8e2afSMika Westerberg         phdr.p_type = PT_LOAD;
4406edf8e2afSMika Westerberg         phdr.p_offset = offset;
4407edf8e2afSMika Westerberg         phdr.p_vaddr = vma->vma_start;
4408edf8e2afSMika Westerberg         phdr.p_paddr = 0;
4409edf8e2afSMika Westerberg         phdr.p_filesz = vma_dump_size(vma);
4410edf8e2afSMika Westerberg         offset += phdr.p_filesz;
4411edf8e2afSMika Westerberg         phdr.p_memsz = vma->vma_end - vma->vma_start;
4412edf8e2afSMika Westerberg         phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
4413edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_WRITE)
4414edf8e2afSMika Westerberg             phdr.p_flags |= PF_W;
4415edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_EXEC)
4416edf8e2afSMika Westerberg             phdr.p_flags |= PF_X;
4417edf8e2afSMika Westerberg         phdr.p_align = ELF_EXEC_PAGESIZE;
4418edf8e2afSMika Westerberg 
441980f5ce75SLaurent Vivier         bswap_phdr(&phdr, 1);
4420772034b6SPeter Maydell         if (dump_write(fd, &phdr, sizeof(phdr)) != 0) {
4421772034b6SPeter Maydell             goto out;
4422772034b6SPeter Maydell         }
4423edf8e2afSMika Westerberg     }
4424edf8e2afSMika Westerberg 
4425edf8e2afSMika Westerberg     /*
4426edf8e2afSMika Westerberg      * Next we write notes just after program headers.  No
4427edf8e2afSMika Westerberg      * alignment needed here.
4428edf8e2afSMika Westerberg      */
4429edf8e2afSMika Westerberg     if (write_note_info(&info, fd) < 0)
4430edf8e2afSMika Westerberg         goto out;
4431edf8e2afSMika Westerberg 
4432edf8e2afSMika Westerberg     /* align data to page boundary */
4433edf8e2afSMika Westerberg     if (lseek(fd, data_offset, SEEK_SET) != data_offset)
4434edf8e2afSMika Westerberg         goto out;
4435edf8e2afSMika Westerberg 
4436edf8e2afSMika Westerberg     /*
4437edf8e2afSMika Westerberg      * Finally we can dump process memory into corefile as well.
4438edf8e2afSMika Westerberg      */
4439edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4440edf8e2afSMika Westerberg         abi_ulong addr;
4441edf8e2afSMika Westerberg         abi_ulong end;
4442edf8e2afSMika Westerberg 
4443edf8e2afSMika Westerberg         end = vma->vma_start + vma_dump_size(vma);
4444edf8e2afSMika Westerberg 
4445edf8e2afSMika Westerberg         for (addr = vma->vma_start; addr < end;
4446edf8e2afSMika Westerberg              addr += TARGET_PAGE_SIZE) {
4447edf8e2afSMika Westerberg             char page[TARGET_PAGE_SIZE];
4448edf8e2afSMika Westerberg             int error;
4449edf8e2afSMika Westerberg 
4450edf8e2afSMika Westerberg             /*
4451edf8e2afSMika Westerberg              *  Read in page from target process memory and
4452edf8e2afSMika Westerberg              *  write it to coredump file.
4453edf8e2afSMika Westerberg              */
4454edf8e2afSMika Westerberg             error = copy_from_user(page, addr, sizeof (page));
4455edf8e2afSMika Westerberg             if (error != 0) {
445649995e17SAurelien Jarno                 (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
4457edf8e2afSMika Westerberg                                addr);
4458edf8e2afSMika Westerberg                 errno = -error;
4459edf8e2afSMika Westerberg                 goto out;
4460edf8e2afSMika Westerberg             }
4461edf8e2afSMika Westerberg             if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
4462edf8e2afSMika Westerberg                 goto out;
4463edf8e2afSMika Westerberg         }
4464edf8e2afSMika Westerberg     }
4465edf8e2afSMika Westerberg 
4466edf8e2afSMika Westerberg  out:
4467edf8e2afSMika Westerberg     free_note_info(&info);
4468edf8e2afSMika Westerberg     if (mm != NULL)
4469edf8e2afSMika Westerberg         vma_delete(mm);
4470edf8e2afSMika Westerberg     (void) close(fd);
4471edf8e2afSMika Westerberg 
4472edf8e2afSMika Westerberg     if (errno != 0)
4473edf8e2afSMika Westerberg         return (-errno);
4474edf8e2afSMika Westerberg     return (0);
4475edf8e2afSMika Westerberg }
4476edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
4477edf8e2afSMika Westerberg 
4478e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
4479e5fe0c52Spbrook {
4480e5fe0c52Spbrook     init_thread(regs, infop);
4481e5fe0c52Spbrook }
4482