xref: /qemu/linux-user/elfload.c (revision 4fd71d19acd6e05b74927a0b5c4a5b0650e3d6f5)
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 
50ea731dbSThomas Weißschuh #include <sys/prctl.h>
6edf8e2afSMika Westerberg #include <sys/resource.h>
730ab9ef2SRichard Henderson #include <sys/shm.h>
831e31b8aSbellard 
93ef693a0Sbellard #include "qemu.h"
1082723866SPhilippe Mathieu-Daudé #include "user/tswap-target.h"
1174781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
1216aa8eaaSPhilippe Mathieu-Daudé #include "user/guest-base.h"
133b249d26SPeter Maydell #include "user-internals.h"
14db2af69dSRichard Henderson #include "signal-common.h"
153ad0a769SPeter Maydell #include "loader.h"
165423e6d3SPeter Maydell #include "user-mmap.h"
1776cad711SPaolo Bonzini #include "disas/disas.h"
18ce543844SPhilippe Mathieu-Daudé #include "qemu/bitops.h"
19f348b6d1SVeronia Bahaa #include "qemu/path.h"
20dc5e9ac7SMarkus Armbruster #include "qemu/queue.h"
21c6a2377fSRichard Henderson #include "qemu/guest-random.h"
226fd59449SRichard Henderson #include "qemu/units.h"
23ee947430SAlex Bennée #include "qemu/selfmap.h"
24370ed600SJamie Iles #include "qemu/lockable.h"
25c7f17e7bSRichard Henderson #include "qapi/error.h"
26cc37d98bSRichard Henderson #include "qemu/error-report.h"
27db2af69dSRichard Henderson #include "target_signal.h"
28327b75a4SIlya Leoshkevich #include "tcg/debuginfo.h"
2931e31b8aSbellard 
305a534314SPeter Maydell #ifdef TARGET_ARM
315a534314SPeter Maydell #include "target/arm/cpu-features.h"
325a534314SPeter Maydell #endif
335a534314SPeter Maydell 
34e58ffeb3Smalc #ifdef _ARCH_PPC64
35a6cc84f4Smalc #undef ARCH_DLINFO
36a6cc84f4Smalc #undef ELF_PLATFORM
37a6cc84f4Smalc #undef ELF_HWCAP
38ad6919dcSPeter Maydell #undef ELF_HWCAP2
39a6cc84f4Smalc #undef ELF_CLASS
40a6cc84f4Smalc #undef ELF_DATA
41a6cc84f4Smalc #undef ELF_ARCH
42a6cc84f4Smalc #endif
43a6cc84f4Smalc 
44c40f621aSRichard Henderson #ifndef TARGET_ARCH_HAS_SIGTRAMP_PAGE
45c40f621aSRichard Henderson #define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
46c40f621aSRichard Henderson #endif
47c40f621aSRichard Henderson 
48c40f621aSRichard Henderson typedef struct {
49c40f621aSRichard Henderson     const uint8_t *image;
50c40f621aSRichard Henderson     const uint32_t *relocs;
51c40f621aSRichard Henderson     unsigned image_size;
52c40f621aSRichard Henderson     unsigned reloc_count;
53c40f621aSRichard Henderson     unsigned sigreturn_ofs;
54c40f621aSRichard Henderson     unsigned rt_sigreturn_ofs;
55c40f621aSRichard Henderson } VdsoImageInfo;
56c40f621aSRichard Henderson 
57edf8e2afSMika Westerberg #define ELF_OSABI   ELFOSABI_SYSV
58edf8e2afSMika Westerberg 
59cb33da57Sblueswir1 /* from personality.h */
60cb33da57Sblueswir1 
61cb33da57Sblueswir1 /*
62cb33da57Sblueswir1  * Flags for bug emulation.
63cb33da57Sblueswir1  *
64cb33da57Sblueswir1  * These occupy the top three bytes.
65cb33da57Sblueswir1  */
66cb33da57Sblueswir1 enum {
67cb33da57Sblueswir1     ADDR_NO_RANDOMIZE = 0x0040000,      /* disable randomization of VA space */
68d97ef72eSRichard Henderson     FDPIC_FUNCPTRS =    0x0080000,      /* userspace function ptrs point to
69d97ef72eSRichard Henderson                                            descriptors (signal handling) */
70cb33da57Sblueswir1     MMAP_PAGE_ZERO =    0x0100000,
71cb33da57Sblueswir1     ADDR_COMPAT_LAYOUT = 0x0200000,
72cb33da57Sblueswir1     READ_IMPLIES_EXEC = 0x0400000,
73cb33da57Sblueswir1     ADDR_LIMIT_32BIT =  0x0800000,
74cb33da57Sblueswir1     SHORT_INODE =       0x1000000,
75cb33da57Sblueswir1     WHOLE_SECONDS =     0x2000000,
76cb33da57Sblueswir1     STICKY_TIMEOUTS =   0x4000000,
77cb33da57Sblueswir1     ADDR_LIMIT_3GB =    0x8000000,
78cb33da57Sblueswir1 };
79cb33da57Sblueswir1 
80cb33da57Sblueswir1 /*
81cb33da57Sblueswir1  * Personality types.
82cb33da57Sblueswir1  *
83cb33da57Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
84cb33da57Sblueswir1  * conflict with error returns.
85cb33da57Sblueswir1  */
86cb33da57Sblueswir1 enum {
87cb33da57Sblueswir1     PER_LINUX =         0x0000,
88cb33da57Sblueswir1     PER_LINUX_32BIT =   0x0000 | ADDR_LIMIT_32BIT,
89cb33da57Sblueswir1     PER_LINUX_FDPIC =   0x0000 | FDPIC_FUNCPTRS,
90cb33da57Sblueswir1     PER_SVR4 =          0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
91cb33da57Sblueswir1     PER_SVR3 =          0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
92d97ef72eSRichard Henderson     PER_SCOSVR3 =       0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE,
93cb33da57Sblueswir1     PER_OSR5 =          0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
94cb33da57Sblueswir1     PER_WYSEV386 =      0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
95cb33da57Sblueswir1     PER_ISCR4 =         0x0005 | STICKY_TIMEOUTS,
96cb33da57Sblueswir1     PER_BSD =           0x0006,
97cb33da57Sblueswir1     PER_SUNOS =         0x0006 | STICKY_TIMEOUTS,
98cb33da57Sblueswir1     PER_XENIX =         0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
99cb33da57Sblueswir1     PER_LINUX32 =       0x0008,
100cb33da57Sblueswir1     PER_LINUX32_3GB =   0x0008 | ADDR_LIMIT_3GB,
101cb33da57Sblueswir1     PER_IRIX32 =        0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
102cb33da57Sblueswir1     PER_IRIXN32 =       0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
103cb33da57Sblueswir1     PER_IRIX64 =        0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
104cb33da57Sblueswir1     PER_RISCOS =        0x000c,
105cb33da57Sblueswir1     PER_SOLARIS =       0x000d | STICKY_TIMEOUTS,
106cb33da57Sblueswir1     PER_UW7 =           0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
107cb33da57Sblueswir1     PER_OSF4 =          0x000f,                  /* OSF/1 v4 */
108cb33da57Sblueswir1     PER_HPUX =          0x0010,
109cb33da57Sblueswir1     PER_MASK =          0x00ff,
110cb33da57Sblueswir1 };
111cb33da57Sblueswir1 
112cb33da57Sblueswir1 /*
113cb33da57Sblueswir1  * Return the base personality without flags.
114cb33da57Sblueswir1  */
115cb33da57Sblueswir1 #define personality(pers)       (pers & PER_MASK)
116cb33da57Sblueswir1 
1173cb10cfaSChristophe Lyon int info_is_fdpic(struct image_info *info)
1183cb10cfaSChristophe Lyon {
1193cb10cfaSChristophe Lyon     return info->personality == PER_LINUX_FDPIC;
1203cb10cfaSChristophe Lyon }
1213cb10cfaSChristophe Lyon 
12283fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
12383fb7adfSbellard #ifndef MAP_DENYWRITE
12483fb7adfSbellard #define MAP_DENYWRITE 0
12583fb7adfSbellard #endif
12683fb7adfSbellard 
12783fb7adfSbellard /* should probably go in elf.h */
12883fb7adfSbellard #ifndef ELIBBAD
12983fb7adfSbellard #define ELIBBAD 80
13083fb7adfSbellard #endif
13183fb7adfSbellard 
132ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
13328490231SRichard Henderson #define ELF_DATA        ELFDATA2MSB
13428490231SRichard Henderson #else
13528490231SRichard Henderson #define ELF_DATA        ELFDATA2LSB
13628490231SRichard Henderson #endif
13728490231SRichard Henderson 
138a29f998dSPaolo Bonzini #ifdef TARGET_ABI_MIPSN32
139918fc54cSPaolo Bonzini typedef abi_ullong      target_elf_greg_t;
140918fc54cSPaolo Bonzini #define tswapreg(ptr)   tswap64(ptr)
141a29f998dSPaolo Bonzini #else
142a29f998dSPaolo Bonzini typedef abi_ulong       target_elf_greg_t;
143a29f998dSPaolo Bonzini #define tswapreg(ptr)   tswapal(ptr)
144a29f998dSPaolo Bonzini #endif
145a29f998dSPaolo Bonzini 
14621e807faSNathan Froyd #ifdef USE_UID16
1471ddd592fSPaolo Bonzini typedef abi_ushort      target_uid_t;
1481ddd592fSPaolo Bonzini typedef abi_ushort      target_gid_t;
14921e807faSNathan Froyd #else
150f8fd4fc4SPaolo Bonzini typedef abi_uint        target_uid_t;
151f8fd4fc4SPaolo Bonzini typedef abi_uint        target_gid_t;
15221e807faSNathan Froyd #endif
153f8fd4fc4SPaolo Bonzini typedef abi_int         target_pid_t;
15421e807faSNathan Froyd 
15530ac07d4Sbellard #ifdef TARGET_I386
15630ac07d4Sbellard 
15715338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
15815338fd7Sbellard 
15915338fd7Sbellard static uint32_t get_elf_hwcap(void)
16015338fd7Sbellard {
161a2247f8eSAndreas Färber     X86CPU *cpu = X86_CPU(thread_cpu);
162a2247f8eSAndreas Färber 
163a2247f8eSAndreas Färber     return cpu->env.features[FEAT_1_EDX];
16415338fd7Sbellard }
16515338fd7Sbellard 
16684409ddbSj_mayer #ifdef TARGET_X86_64
16784409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
16884409ddbSj_mayer #define ELF_ARCH       EM_X86_64
16984409ddbSj_mayer 
1709263ba84SRichard Henderson #define ELF_PLATFORM   "x86_64"
1719263ba84SRichard Henderson 
17284409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
17384409ddbSj_mayer {
17484409ddbSj_mayer     regs->rax = 0;
17584409ddbSj_mayer     regs->rsp = infop->start_stack;
17684409ddbSj_mayer     regs->rip = infop->entry;
17784409ddbSj_mayer }
17884409ddbSj_mayer 
1799edc5d79SMika Westerberg #define ELF_NREG    27
180c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
1819edc5d79SMika Westerberg 
1829edc5d79SMika Westerberg /*
1839edc5d79SMika Westerberg  * Note that ELF_NREG should be 29 as there should be place for
1849edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
1859edc5d79SMika Westerberg  * those.
1869edc5d79SMika Westerberg  *
1879edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
1889edc5d79SMika Westerberg  */
18905390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
1909edc5d79SMika Westerberg {
191030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[15]);
192030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[14]);
193030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[13]);
194030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[12]);
195030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EBP]);
196030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBX]);
197030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[11]);
198030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->regs[10]);
199030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->regs[9]);
200030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->regs[8]);
201030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->regs[R_EAX]);
202030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_ECX]);
203030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->regs[R_EDX]);
204030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->regs[R_ESI]);
205030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->regs[R_EDI]);
206030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_EAX]); /* XXX */
207030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->eip);
208030912e0SIlya Leoshkevich     (*regs)[17] = tswapreg(env->segs[R_CS].selector & 0xffff);
209030912e0SIlya Leoshkevich     (*regs)[18] = tswapreg(env->eflags);
210030912e0SIlya Leoshkevich     (*regs)[19] = tswapreg(env->regs[R_ESP]);
211030912e0SIlya Leoshkevich     (*regs)[20] = tswapreg(env->segs[R_SS].selector & 0xffff);
212030912e0SIlya Leoshkevich     (*regs)[21] = tswapreg(env->segs[R_FS].selector & 0xffff);
213030912e0SIlya Leoshkevich     (*regs)[22] = tswapreg(env->segs[R_GS].selector & 0xffff);
214030912e0SIlya Leoshkevich     (*regs)[23] = tswapreg(env->segs[R_DS].selector & 0xffff);
215030912e0SIlya Leoshkevich     (*regs)[24] = tswapreg(env->segs[R_ES].selector & 0xffff);
216030912e0SIlya Leoshkevich     (*regs)[25] = tswapreg(env->segs[R_FS].selector & 0xffff);
217030912e0SIlya Leoshkevich     (*regs)[26] = tswapreg(env->segs[R_GS].selector & 0xffff);
2189edc5d79SMika Westerberg }
2199edc5d79SMika Westerberg 
220d461b73eSRichard Henderson #if ULONG_MAX > UINT32_MAX
221d461b73eSRichard Henderson #define INIT_GUEST_COMMPAGE
222d461b73eSRichard Henderson static bool init_guest_commpage(void)
223d461b73eSRichard Henderson {
224d461b73eSRichard Henderson     /*
225d461b73eSRichard Henderson      * The vsyscall page is at a high negative address aka kernel space,
226d461b73eSRichard Henderson      * which means that we cannot actually allocate it with target_mmap.
227d461b73eSRichard Henderson      * We still should be able to use page_set_flags, unless the user
228d461b73eSRichard Henderson      * has specified -R reserved_va, which would trigger an assert().
229d461b73eSRichard Henderson      */
230d461b73eSRichard Henderson     if (reserved_va != 0 &&
23195059f9cSRichard Henderson         TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE - 1 > reserved_va) {
232d461b73eSRichard Henderson         error_report("Cannot allocate vsyscall page");
233d461b73eSRichard Henderson         exit(EXIT_FAILURE);
234d461b73eSRichard Henderson     }
235d461b73eSRichard Henderson     page_set_flags(TARGET_VSYSCALL_PAGE,
23649840a4aSRichard Henderson                    TARGET_VSYSCALL_PAGE | ~TARGET_PAGE_MASK,
237d461b73eSRichard Henderson                    PAGE_EXEC | PAGE_VALID);
238d461b73eSRichard Henderson     return true;
239d461b73eSRichard Henderson }
240d461b73eSRichard Henderson #endif
24184409ddbSj_mayer #else
24284409ddbSj_mayer 
24330ac07d4Sbellard /*
24430ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
24530ac07d4Sbellard  */
24630ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
24730ac07d4Sbellard 
24830ac07d4Sbellard /*
24930ac07d4Sbellard  * These are used to set parameters in the core dumps.
25030ac07d4Sbellard  */
25130ac07d4Sbellard #define ELF_CLASS       ELFCLASS32
25230ac07d4Sbellard #define ELF_ARCH        EM_386
25330ac07d4Sbellard 
2549263ba84SRichard Henderson #define ELF_PLATFORM get_elf_platform()
255872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
2569263ba84SRichard Henderson 
2579263ba84SRichard Henderson static const char *get_elf_platform(void)
2589263ba84SRichard Henderson {
2599263ba84SRichard Henderson     static char elf_platform[] = "i386";
2609263ba84SRichard Henderson     int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
2619263ba84SRichard Henderson     if (family > 6) {
2629263ba84SRichard Henderson         family = 6;
2639263ba84SRichard Henderson     }
2649263ba84SRichard Henderson     if (family >= 3) {
2659263ba84SRichard Henderson         elf_platform[1] = '0' + family;
2669263ba84SRichard Henderson     }
2679263ba84SRichard Henderson     return elf_platform;
2689263ba84SRichard Henderson }
2699263ba84SRichard Henderson 
270d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
271d97ef72eSRichard Henderson                                struct image_info *infop)
272e5fe0c52Spbrook {
273e5fe0c52Spbrook     regs->esp = infop->start_stack;
274e5fe0c52Spbrook     regs->eip = infop->entry;
275e5fe0c52Spbrook 
27630ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
27730ac07d4Sbellard        starts %edx contains a pointer to a function which might be
27830ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
27930ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
28030ac07d4Sbellard        that have been loaded before the code runs.
28130ac07d4Sbellard 
28230ac07d4Sbellard        A value of 0 tells we have no such handler.  */
283e5fe0c52Spbrook     regs->edx = 0;
284b346ff46Sbellard }
2859edc5d79SMika Westerberg 
2869edc5d79SMika Westerberg #define ELF_NREG    17
287c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
2889edc5d79SMika Westerberg 
2899edc5d79SMika Westerberg /*
2909edc5d79SMika Westerberg  * Note that ELF_NREG should be 19 as there should be place for
2919edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
2929edc5d79SMika Westerberg  * those.
2939edc5d79SMika Westerberg  *
2949edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
2959edc5d79SMika Westerberg  */
29605390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
2979edc5d79SMika Westerberg {
298030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[R_EBX]);
299030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[R_ECX]);
300030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[R_EDX]);
301030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[R_ESI]);
302030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EDI]);
303030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBP]);
304030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[R_EAX]);
305030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->segs[R_DS].selector & 0xffff);
306030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->segs[R_ES].selector & 0xffff);
307030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->segs[R_FS].selector & 0xffff);
308030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->segs[R_GS].selector & 0xffff);
309030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_EAX]); /* XXX */
310030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->eip);
311030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->segs[R_CS].selector & 0xffff);
312030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->eflags);
313030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_ESP]);
314030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->segs[R_SS].selector & 0xffff);
3159edc5d79SMika Westerberg }
316a1367443SRichard Henderson 
317a1367443SRichard Henderson /*
318a1367443SRichard Henderson  * i386 is the only target which supplies AT_SYSINFO for the vdso.
319a1367443SRichard Henderson  * All others only supply AT_SYSINFO_EHDR.
320a1367443SRichard Henderson  */
321a1367443SRichard Henderson #define DLINFO_ARCH_ITEMS (vdso_info != NULL)
322a1367443SRichard Henderson #define ARCH_DLINFO                                     \
323a1367443SRichard Henderson     do {                                                \
324a1367443SRichard Henderson         if (vdso_info) {                                \
325a1367443SRichard Henderson             NEW_AUX_ENT(AT_SYSINFO, vdso_info->entry);  \
326a1367443SRichard Henderson         }                                               \
327a1367443SRichard Henderson     } while (0)
328a1367443SRichard Henderson 
329a1367443SRichard Henderson #endif /* TARGET_X86_64 */
330b346ff46Sbellard 
3316b1a9d38SRichard Henderson #define VDSO_HEADER "vdso.c.inc"
332b346ff46Sbellard 
3339edc5d79SMika Westerberg #define USE_ELF_CORE_DUMP
334b346ff46Sbellard #define ELF_EXEC_PAGESIZE       4096
335b346ff46Sbellard 
336a1367443SRichard Henderson #endif /* TARGET_I386 */
337b346ff46Sbellard 
338b346ff46Sbellard #ifdef TARGET_ARM
339b346ff46Sbellard 
34024e76ff0SPeter Maydell #ifndef TARGET_AARCH64
34124e76ff0SPeter Maydell /* 32 bit ARM definitions */
34224e76ff0SPeter Maydell 
343b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_ARM
344b346ff46Sbellard #define ELF_CLASS       ELFCLASS32
345872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
346b346ff46Sbellard 
347d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
348d97ef72eSRichard Henderson                                struct image_info *infop)
349b346ff46Sbellard {
350992f48a0Sblueswir1     abi_long stack = infop->start_stack;
351b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
35299033caeSAlexander Graf 
353167e4cdcSPeter Maydell     regs->uregs[16] = ARM_CPU_MODE_USR;
354167e4cdcSPeter Maydell     if (infop->entry & 1) {
355167e4cdcSPeter Maydell         regs->uregs[16] |= CPSR_T;
356167e4cdcSPeter Maydell     }
357167e4cdcSPeter Maydell     regs->uregs[15] = infop->entry & 0xfffffffe;
358167e4cdcSPeter Maydell     regs->uregs[13] = infop->start_stack;
3592f619698Sbellard     /* FIXME - what to for failure of get_user()? */
360167e4cdcSPeter Maydell     get_user_ual(regs->uregs[2], stack + 8); /* envp */
361167e4cdcSPeter Maydell     get_user_ual(regs->uregs[1], stack + 4); /* envp */
362a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
363167e4cdcSPeter Maydell     regs->uregs[0] = 0;
364e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
365863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
366167e4cdcSPeter Maydell     regs->uregs[10] = infop->start_data;
3673cb10cfaSChristophe Lyon 
3683cb10cfaSChristophe Lyon     /* Support ARM FDPIC.  */
3693cb10cfaSChristophe Lyon     if (info_is_fdpic(infop)) {
3703cb10cfaSChristophe Lyon         /* As described in the ABI document, r7 points to the loadmap info
3713cb10cfaSChristophe Lyon          * prepared by the kernel. If an interpreter is needed, r8 points
3723cb10cfaSChristophe Lyon          * to the interpreter loadmap and r9 points to the interpreter
3733cb10cfaSChristophe Lyon          * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
3743cb10cfaSChristophe Lyon          * r9 points to the main program PT_DYNAMIC info.
3753cb10cfaSChristophe Lyon          */
3763cb10cfaSChristophe Lyon         regs->uregs[7] = infop->loadmap_addr;
3773cb10cfaSChristophe Lyon         if (infop->interpreter_loadmap_addr) {
3783cb10cfaSChristophe Lyon             /* Executable is dynamically loaded.  */
3793cb10cfaSChristophe Lyon             regs->uregs[8] = infop->interpreter_loadmap_addr;
3803cb10cfaSChristophe Lyon             regs->uregs[9] = infop->interpreter_pt_dynamic_addr;
3813cb10cfaSChristophe Lyon         } else {
3823cb10cfaSChristophe Lyon             regs->uregs[8] = 0;
3833cb10cfaSChristophe Lyon             regs->uregs[9] = infop->pt_dynamic_addr;
3843cb10cfaSChristophe Lyon         }
3853cb10cfaSChristophe Lyon     }
386b346ff46Sbellard }
387b346ff46Sbellard 
388edf8e2afSMika Westerberg #define ELF_NREG    18
389c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
390edf8e2afSMika Westerberg 
39105390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUARMState *env)
392edf8e2afSMika Westerberg {
39386cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->regs[0]);
39486cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->regs[1]);
39586cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->regs[2]);
39686cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->regs[3]);
39786cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->regs[4]);
39886cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->regs[5]);
39986cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->regs[6]);
40086cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->regs[7]);
40186cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->regs[8]);
40286cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->regs[9]);
40386cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->regs[10]);
40486cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->regs[11]);
40586cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->regs[12]);
40686cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->regs[13]);
40786cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->regs[14]);
40886cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->regs[15]);
409edf8e2afSMika Westerberg 
41086cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(cpsr_read((CPUARMState *)env));
41186cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->regs[0]); /* XXX */
412edf8e2afSMika Westerberg }
413edf8e2afSMika Westerberg 
41430ac07d4Sbellard #define USE_ELF_CORE_DUMP
41530ac07d4Sbellard #define ELF_EXEC_PAGESIZE       4096
41630ac07d4Sbellard 
417afce2927Sbellard enum
418afce2927Sbellard {
419afce2927Sbellard     ARM_HWCAP_ARM_SWP       = 1 << 0,
420afce2927Sbellard     ARM_HWCAP_ARM_HALF      = 1 << 1,
421afce2927Sbellard     ARM_HWCAP_ARM_THUMB     = 1 << 2,
422afce2927Sbellard     ARM_HWCAP_ARM_26BIT     = 1 << 3,
423afce2927Sbellard     ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
424afce2927Sbellard     ARM_HWCAP_ARM_FPA       = 1 << 5,
425afce2927Sbellard     ARM_HWCAP_ARM_VFP       = 1 << 6,
426afce2927Sbellard     ARM_HWCAP_ARM_EDSP      = 1 << 7,
427cf6de34aSRiku Voipio     ARM_HWCAP_ARM_JAVA      = 1 << 8,
428cf6de34aSRiku Voipio     ARM_HWCAP_ARM_IWMMXT    = 1 << 9,
42943ce393eSPeter Maydell     ARM_HWCAP_ARM_CRUNCH    = 1 << 10,
43043ce393eSPeter Maydell     ARM_HWCAP_ARM_THUMBEE   = 1 << 11,
43143ce393eSPeter Maydell     ARM_HWCAP_ARM_NEON      = 1 << 12,
43243ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3     = 1 << 13,
43343ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3D16  = 1 << 14,
43424682654SPeter Maydell     ARM_HWCAP_ARM_TLS       = 1 << 15,
43524682654SPeter Maydell     ARM_HWCAP_ARM_VFPv4     = 1 << 16,
43624682654SPeter Maydell     ARM_HWCAP_ARM_IDIVA     = 1 << 17,
43724682654SPeter Maydell     ARM_HWCAP_ARM_IDIVT     = 1 << 18,
43824682654SPeter Maydell     ARM_HWCAP_ARM_VFPD32    = 1 << 19,
43924682654SPeter Maydell     ARM_HWCAP_ARM_LPAE      = 1 << 20,
44024682654SPeter Maydell     ARM_HWCAP_ARM_EVTSTRM   = 1 << 21,
44123d7f14dSPeter Maydell     ARM_HWCAP_ARM_FPHP      = 1 << 22,
44223d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDHP   = 1 << 23,
44323d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDDP   = 1 << 24,
44423d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDFHM  = 1 << 25,
44523d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDBF16 = 1 << 26,
44623d7f14dSPeter Maydell     ARM_HWCAP_ARM_I8MM      = 1 << 27,
447afce2927Sbellard };
448afce2927Sbellard 
449ad6919dcSPeter Maydell enum {
450ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_AES      = 1 << 0,
451ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_PMULL    = 1 << 1,
452ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA1     = 1 << 2,
453ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA2     = 1 << 3,
454ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_CRC32    = 1 << 4,
45523d7f14dSPeter Maydell     ARM_HWCAP2_ARM_SB       = 1 << 5,
45623d7f14dSPeter Maydell     ARM_HWCAP2_ARM_SSBS     = 1 << 6,
457ad6919dcSPeter Maydell };
458ad6919dcSPeter Maydell 
4596b1275ffSPeter Maydell /* The commpage only exists for 32 bit kernels */
4606b1275ffSPeter Maydell 
46166346fafSRichard Henderson #define HI_COMMPAGE (intptr_t)0xffff0f00u
462ee947430SAlex Bennée 
463ee947430SAlex Bennée static bool init_guest_commpage(void)
46497cc7560SDr. David Alan Gilbert {
465d713cf4dSPhilippe Mathieu-Daudé     ARMCPU *cpu = ARM_CPU(thread_cpu);
4662cd71515SRichard Henderson     int host_page_size = qemu_real_host_page_size();
467d713cf4dSPhilippe Mathieu-Daudé     abi_ptr commpage;
468d713cf4dSPhilippe Mathieu-Daudé     void *want;
469d713cf4dSPhilippe Mathieu-Daudé     void *addr;
470d713cf4dSPhilippe Mathieu-Daudé 
471d713cf4dSPhilippe Mathieu-Daudé     /*
472d713cf4dSPhilippe Mathieu-Daudé      * M-profile allocates maximum of 2GB address space, so can never
473d713cf4dSPhilippe Mathieu-Daudé      * allocate the commpage.  Skip it.
474d713cf4dSPhilippe Mathieu-Daudé      */
475d713cf4dSPhilippe Mathieu-Daudé     if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
476d713cf4dSPhilippe Mathieu-Daudé         return true;
477d713cf4dSPhilippe Mathieu-Daudé     }
478d713cf4dSPhilippe Mathieu-Daudé 
4792cd71515SRichard Henderson     commpage = HI_COMMPAGE & -host_page_size;
480d713cf4dSPhilippe Mathieu-Daudé     want = g2h_untagged(commpage);
4812cd71515SRichard Henderson     addr = mmap(want, host_page_size, PROT_READ | PROT_WRITE,
4822cd71515SRichard Henderson                 MAP_ANONYMOUS | MAP_PRIVATE |
4832cd71515SRichard Henderson                 (commpage < reserved_va ? MAP_FIXED : MAP_FIXED_NOREPLACE),
4842cd71515SRichard Henderson                 -1, 0);
48597cc7560SDr. David Alan Gilbert 
4866cda41daSRichard Henderson     if (addr == MAP_FAILED) {
487ee947430SAlex Bennée         perror("Allocating guest commpage");
488ee947430SAlex Bennée         exit(EXIT_FAILURE);
489ee947430SAlex Bennée     }
490ee947430SAlex Bennée     if (addr != want) {
491ee947430SAlex Bennée         return false;
492806d1021SMeador Inge     }
493806d1021SMeador Inge 
494ee947430SAlex Bennée     /* Set kernel helper versions; rest of page is 0.  */
4956cda41daSRichard Henderson     __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu));
49697cc7560SDr. David Alan Gilbert 
4972cd71515SRichard Henderson     if (mprotect(addr, host_page_size, PROT_READ)) {
49897cc7560SDr. David Alan Gilbert         perror("Protecting guest commpage");
499ee947430SAlex Bennée         exit(EXIT_FAILURE);
50097cc7560SDr. David Alan Gilbert     }
5016cda41daSRichard Henderson 
5022cd71515SRichard Henderson     page_set_flags(commpage, commpage | (host_page_size - 1),
5036cda41daSRichard Henderson                    PAGE_READ | PAGE_EXEC | PAGE_VALID);
504ee947430SAlex Bennée     return true;
50597cc7560SDr. David Alan Gilbert }
506adf050b1SBenoit Canet 
507adf050b1SBenoit Canet #define ELF_HWCAP get_elf_hwcap()
508ad6919dcSPeter Maydell #define ELF_HWCAP2 get_elf_hwcap2()
509adf050b1SBenoit Canet 
510a55b9e72SHelge Deller uint32_t get_elf_hwcap(void)
511adf050b1SBenoit Canet {
512a2247f8eSAndreas Färber     ARMCPU *cpu = ARM_CPU(thread_cpu);
513adf050b1SBenoit Canet     uint32_t hwcaps = 0;
514adf050b1SBenoit Canet 
515adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_SWP;
516adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_HALF;
517adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_THUMB;
518adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
519adf050b1SBenoit Canet 
520adf050b1SBenoit Canet     /* probe for the extra features */
521adf050b1SBenoit Canet #define GET_FEATURE(feat, hwcap) \
522a2247f8eSAndreas Färber     do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
523962fcbf2SRichard Henderson 
524962fcbf2SRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
525962fcbf2SRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
526962fcbf2SRichard Henderson 
52724682654SPeter Maydell     /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
52824682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
529adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
530adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
531adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
53224682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
533bfa8a370SRichard Henderson     GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
534873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
535873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
536bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP);
537bfa8a370SRichard Henderson 
538bfa8a370SRichard Henderson     if (cpu_isar_feature(aa32_fpsp_v3, cpu) ||
539bfa8a370SRichard Henderson         cpu_isar_feature(aa32_fpdp_v3, cpu)) {
540bfa8a370SRichard Henderson         hwcaps |= ARM_HWCAP_ARM_VFPv3;
541bfa8a370SRichard Henderson         if (cpu_isar_feature(aa32_simd_r32, cpu)) {
542bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPD32;
543bfa8a370SRichard Henderson         } else {
544bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPv3D16;
545bfa8a370SRichard Henderson         }
546bfa8a370SRichard Henderson     }
547bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4);
548429b7e01SPeter Maydell     /*
549429b7e01SPeter Maydell      * MVFR1.FPHP and .SIMDHP must be in sync, and QEMU uses the same
550429b7e01SPeter Maydell      * isar_feature function for both. The kernel reports them as two hwcaps.
551429b7e01SPeter Maydell      */
552429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_FPHP);
553429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_ASIMDHP);
554429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_dp, ARM_HWCAP_ARM_ASIMDDP);
555429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fhm, ARM_HWCAP_ARM_ASIMDFHM);
556429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_bf16, ARM_HWCAP_ARM_ASIMDBF16);
557429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_i8mm, ARM_HWCAP_ARM_I8MM);
558adf050b1SBenoit Canet 
559adf050b1SBenoit Canet     return hwcaps;
560adf050b1SBenoit Canet }
561afce2927Sbellard 
56263c1b7deSPeter Maydell uint64_t get_elf_hwcap2(void)
563ad6919dcSPeter Maydell {
564ad6919dcSPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
56563c1b7deSPeter Maydell     uint64_t hwcaps = 0;
566ad6919dcSPeter Maydell 
567962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_aes, ARM_HWCAP2_ARM_AES);
568962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_pmull, ARM_HWCAP2_ARM_PMULL);
569962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha1, ARM_HWCAP2_ARM_SHA1);
570962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha2, ARM_HWCAP2_ARM_SHA2);
571962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_crc32, ARM_HWCAP2_ARM_CRC32);
572429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_sb, ARM_HWCAP2_ARM_SB);
573429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_ssbs, ARM_HWCAP2_ARM_SSBS);
574ad6919dcSPeter Maydell     return hwcaps;
575ad6919dcSPeter Maydell }
576ad6919dcSPeter Maydell 
577a55b9e72SHelge Deller const char *elf_hwcap_str(uint32_t bit)
578a55b9e72SHelge Deller {
579a55b9e72SHelge Deller     static const char *hwcap_str[] = {
580a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_SWP      )] = "swp",
581a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_HALF     )] = "half",
582a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_THUMB    )] = "thumb",
583a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_26BIT    )] = "26bit",
584a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_FAST_MULT)] = "fast_mult",
585a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_FPA      )] = "fpa",
586a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFP      )] = "vfp",
587a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_EDSP     )] = "edsp",
588a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_JAVA     )] = "java",
589a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IWMMXT   )] = "iwmmxt",
590a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_CRUNCH   )] = "crunch",
591a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_THUMBEE  )] = "thumbee",
592a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_NEON     )] = "neon",
593a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv3    )] = "vfpv3",
594a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv3D16 )] = "vfpv3d16",
595a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_TLS      )] = "tls",
596a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv4    )] = "vfpv4",
597a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IDIVA    )] = "idiva",
598a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IDIVT    )] = "idivt",
599a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPD32   )] = "vfpd32",
600a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_LPAE     )] = "lpae",
601a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_EVTSTRM  )] = "evtstrm",
60223d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_FPHP     )] = "fphp",
60323d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDHP  )] = "asimdhp",
60423d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDDP  )] = "asimddp",
60523d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDFHM )] = "asimdfhm",
60623d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDBF16)] = "asimdbf16",
60723d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_I8MM     )] = "i8mm",
608a55b9e72SHelge Deller     };
609a55b9e72SHelge Deller 
610a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
611a55b9e72SHelge Deller }
612a55b9e72SHelge Deller 
613a55b9e72SHelge Deller const char *elf_hwcap2_str(uint32_t bit)
614a55b9e72SHelge Deller {
615a55b9e72SHelge Deller     static const char *hwcap_str[] = {
616a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_AES  )] = "aes",
617a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_PMULL)] = "pmull",
618a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_SHA1 )] = "sha1",
619a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_SHA2 )] = "sha2",
620a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_CRC32)] = "crc32",
62123d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_ARM_SB   )] = "sb",
62223d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_ARM_SSBS )] = "ssbs",
623a55b9e72SHelge Deller     };
624a55b9e72SHelge Deller 
625a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
626a55b9e72SHelge Deller }
627a55b9e72SHelge Deller 
628ad6919dcSPeter Maydell #undef GET_FEATURE
629962fcbf2SRichard Henderson #undef GET_FEATURE_ID
630ad6919dcSPeter Maydell 
63113ec4ec3SRichard Henderson #define ELF_PLATFORM get_elf_platform()
63213ec4ec3SRichard Henderson 
63313ec4ec3SRichard Henderson static const char *get_elf_platform(void)
63413ec4ec3SRichard Henderson {
635b77af26eSRichard Henderson     CPUARMState *env = cpu_env(thread_cpu);
63613ec4ec3SRichard Henderson 
637ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
63813ec4ec3SRichard Henderson # define END  "b"
63913ec4ec3SRichard Henderson #else
64013ec4ec3SRichard Henderson # define END  "l"
64113ec4ec3SRichard Henderson #endif
64213ec4ec3SRichard Henderson 
64313ec4ec3SRichard Henderson     if (arm_feature(env, ARM_FEATURE_V8)) {
64413ec4ec3SRichard Henderson         return "v8" END;
64513ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V7)) {
64613ec4ec3SRichard Henderson         if (arm_feature(env, ARM_FEATURE_M)) {
64713ec4ec3SRichard Henderson             return "v7m" END;
64813ec4ec3SRichard Henderson         } else {
64913ec4ec3SRichard Henderson             return "v7" END;
65013ec4ec3SRichard Henderson         }
65113ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V6)) {
65213ec4ec3SRichard Henderson         return "v6" END;
65313ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V5)) {
65413ec4ec3SRichard Henderson         return "v5" END;
65513ec4ec3SRichard Henderson     } else {
65613ec4ec3SRichard Henderson         return "v4" END;
65713ec4ec3SRichard Henderson     }
65813ec4ec3SRichard Henderson 
65913ec4ec3SRichard Henderson #undef END
66013ec4ec3SRichard Henderson }
66113ec4ec3SRichard Henderson 
66224e76ff0SPeter Maydell #else
66324e76ff0SPeter Maydell /* 64 bit ARM definitions */
66424e76ff0SPeter Maydell 
665b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_AARCH64
66624e76ff0SPeter Maydell #define ELF_CLASS       ELFCLASS64
667ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
668e20e3ec9SRichard Henderson # define ELF_PLATFORM    "aarch64_be"
669e20e3ec9SRichard Henderson #else
67024e76ff0SPeter Maydell # define ELF_PLATFORM    "aarch64"
671e20e3ec9SRichard Henderson #endif
67224e76ff0SPeter Maydell 
67324e76ff0SPeter Maydell static inline void init_thread(struct target_pt_regs *regs,
67424e76ff0SPeter Maydell                                struct image_info *infop)
67524e76ff0SPeter Maydell {
67624e76ff0SPeter Maydell     abi_long stack = infop->start_stack;
67724e76ff0SPeter Maydell     memset(regs, 0, sizeof(*regs));
67824e76ff0SPeter Maydell 
67924e76ff0SPeter Maydell     regs->pc = infop->entry & ~0x3ULL;
68024e76ff0SPeter Maydell     regs->sp = stack;
68124e76ff0SPeter Maydell }
68224e76ff0SPeter Maydell 
68324e76ff0SPeter Maydell #define ELF_NREG    34
68424e76ff0SPeter Maydell typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
68524e76ff0SPeter Maydell 
68624e76ff0SPeter Maydell static void elf_core_copy_regs(target_elf_gregset_t *regs,
68724e76ff0SPeter Maydell                                const CPUARMState *env)
68824e76ff0SPeter Maydell {
68924e76ff0SPeter Maydell     int i;
69024e76ff0SPeter Maydell 
69124e76ff0SPeter Maydell     for (i = 0; i < 32; i++) {
69224e76ff0SPeter Maydell         (*regs)[i] = tswapreg(env->xregs[i]);
69324e76ff0SPeter Maydell     }
69424e76ff0SPeter Maydell     (*regs)[32] = tswapreg(env->pc);
69524e76ff0SPeter Maydell     (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env));
69624e76ff0SPeter Maydell }
69724e76ff0SPeter Maydell 
69824e76ff0SPeter Maydell #define USE_ELF_CORE_DUMP
69924e76ff0SPeter Maydell #define ELF_EXEC_PAGESIZE       4096
70024e76ff0SPeter Maydell 
70124e76ff0SPeter Maydell enum {
70224e76ff0SPeter Maydell     ARM_HWCAP_A64_FP            = 1 << 0,
70324e76ff0SPeter Maydell     ARM_HWCAP_A64_ASIMD         = 1 << 1,
70424e76ff0SPeter Maydell     ARM_HWCAP_A64_EVTSTRM       = 1 << 2,
70524e76ff0SPeter Maydell     ARM_HWCAP_A64_AES           = 1 << 3,
70624e76ff0SPeter Maydell     ARM_HWCAP_A64_PMULL         = 1 << 4,
70724e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA1          = 1 << 5,
70824e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA2          = 1 << 6,
70924e76ff0SPeter Maydell     ARM_HWCAP_A64_CRC32         = 1 << 7,
710955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ATOMICS       = 1 << 8,
711955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FPHP          = 1 << 9,
712955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDHP       = 1 << 10,
713955f56d4SArd Biesheuvel     ARM_HWCAP_A64_CPUID         = 1 << 11,
714955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDRDM      = 1 << 12,
715955f56d4SArd Biesheuvel     ARM_HWCAP_A64_JSCVT         = 1 << 13,
716955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FCMA          = 1 << 14,
717955f56d4SArd Biesheuvel     ARM_HWCAP_A64_LRCPC         = 1 << 15,
718955f56d4SArd Biesheuvel     ARM_HWCAP_A64_DCPOP         = 1 << 16,
719955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA3          = 1 << 17,
720955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM3           = 1 << 18,
721955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM4           = 1 << 19,
722955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDDP       = 1 << 20,
723955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA512        = 1 << 21,
724955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SVE           = 1 << 22,
7250083a1faSRichard Henderson     ARM_HWCAP_A64_ASIMDFHM      = 1 << 23,
7260083a1faSRichard Henderson     ARM_HWCAP_A64_DIT           = 1 << 24,
7270083a1faSRichard Henderson     ARM_HWCAP_A64_USCAT         = 1 << 25,
7280083a1faSRichard Henderson     ARM_HWCAP_A64_ILRCPC        = 1 << 26,
7290083a1faSRichard Henderson     ARM_HWCAP_A64_FLAGM         = 1 << 27,
7300083a1faSRichard Henderson     ARM_HWCAP_A64_SSBS          = 1 << 28,
7310083a1faSRichard Henderson     ARM_HWCAP_A64_SB            = 1 << 29,
7320083a1faSRichard Henderson     ARM_HWCAP_A64_PACA          = 1 << 30,
7330083a1faSRichard Henderson     ARM_HWCAP_A64_PACG          = 1UL << 31,
7342041df4aSRichard Henderson 
7352041df4aSRichard Henderson     ARM_HWCAP2_A64_DCPODP       = 1 << 0,
7362041df4aSRichard Henderson     ARM_HWCAP2_A64_SVE2         = 1 << 1,
7372041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEAES       = 1 << 2,
7382041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEPMULL     = 1 << 3,
7392041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEBITPERM   = 1 << 4,
7402041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESHA3      = 1 << 5,
7412041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESM4       = 1 << 6,
7422041df4aSRichard Henderson     ARM_HWCAP2_A64_FLAGM2       = 1 << 7,
7432041df4aSRichard Henderson     ARM_HWCAP2_A64_FRINT        = 1 << 8,
74468948d18SRichard Henderson     ARM_HWCAP2_A64_SVEI8MM      = 1 << 9,
74568948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF32MM     = 1 << 10,
74668948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF64MM     = 1 << 11,
74768948d18SRichard Henderson     ARM_HWCAP2_A64_SVEBF16      = 1 << 12,
74868948d18SRichard Henderson     ARM_HWCAP2_A64_I8MM         = 1 << 13,
74968948d18SRichard Henderson     ARM_HWCAP2_A64_BF16         = 1 << 14,
75068948d18SRichard Henderson     ARM_HWCAP2_A64_DGH          = 1 << 15,
75168948d18SRichard Henderson     ARM_HWCAP2_A64_RNG          = 1 << 16,
75268948d18SRichard Henderson     ARM_HWCAP2_A64_BTI          = 1 << 17,
75368948d18SRichard Henderson     ARM_HWCAP2_A64_MTE          = 1 << 18,
754f9982ceaSRichard Henderson     ARM_HWCAP2_A64_ECV          = 1 << 19,
755f9982ceaSRichard Henderson     ARM_HWCAP2_A64_AFP          = 1 << 20,
756f9982ceaSRichard Henderson     ARM_HWCAP2_A64_RPRES        = 1 << 21,
757f9982ceaSRichard Henderson     ARM_HWCAP2_A64_MTE3         = 1 << 22,
758f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME          = 1 << 23,
759f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I16I64   = 1 << 24,
760f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F64F64   = 1 << 25,
761f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I8I32    = 1 << 26,
762f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F16F32   = 1 << 27,
763f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_B16F32   = 1 << 28,
764f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F32F32   = 1 << 29,
765f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_FA64     = 1 << 30,
76623d7f14dSPeter Maydell     ARM_HWCAP2_A64_WFXT         = 1ULL << 31,
76723d7f14dSPeter Maydell     ARM_HWCAP2_A64_EBF16        = 1ULL << 32,
76823d7f14dSPeter Maydell     ARM_HWCAP2_A64_SVE_EBF16    = 1ULL << 33,
76923d7f14dSPeter Maydell     ARM_HWCAP2_A64_CSSC         = 1ULL << 34,
77023d7f14dSPeter Maydell     ARM_HWCAP2_A64_RPRFM        = 1ULL << 35,
77123d7f14dSPeter Maydell     ARM_HWCAP2_A64_SVE2P1       = 1ULL << 36,
77223d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME2         = 1ULL << 37,
77323d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME2P1       = 1ULL << 38,
77423d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_I16I32   = 1ULL << 39,
77523d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_BI32I32  = 1ULL << 40,
77623d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_B16B16   = 1ULL << 41,
77723d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_F16F16   = 1ULL << 42,
77823d7f14dSPeter Maydell     ARM_HWCAP2_A64_MOPS         = 1ULL << 43,
77923d7f14dSPeter Maydell     ARM_HWCAP2_A64_HBC          = 1ULL << 44,
78024e76ff0SPeter Maydell };
78124e76ff0SPeter Maydell 
78224e76ff0SPeter Maydell #define ELF_HWCAP   get_elf_hwcap()
7832041df4aSRichard Henderson #define ELF_HWCAP2  get_elf_hwcap2()
7842041df4aSRichard Henderson 
7852041df4aSRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
7862041df4aSRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
78724e76ff0SPeter Maydell 
788a55b9e72SHelge Deller uint32_t get_elf_hwcap(void)
78924e76ff0SPeter Maydell {
79024e76ff0SPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
79124e76ff0SPeter Maydell     uint32_t hwcaps = 0;
79224e76ff0SPeter Maydell 
79324e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_FP;
79424e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_ASIMD;
79537020ff1SAlex Bennée     hwcaps |= ARM_HWCAP_A64_CPUID;
79624e76ff0SPeter Maydell 
79724e76ff0SPeter Maydell     /* probe for the extra features */
798962fcbf2SRichard Henderson 
799962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES);
800962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL);
801962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha1, ARM_HWCAP_A64_SHA1);
802962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha256, ARM_HWCAP_A64_SHA2);
803962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha512, ARM_HWCAP_A64_SHA512);
804962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_crc32, ARM_HWCAP_A64_CRC32);
805962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha3, ARM_HWCAP_A64_SHA3);
806962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm3, ARM_HWCAP_A64_SM3);
807962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm4, ARM_HWCAP_A64_SM4);
8085763190fSRichard Henderson     GET_FEATURE_ID(aa64_fp16, ARM_HWCAP_A64_FPHP | ARM_HWCAP_A64_ASIMDHP);
809962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_atomics, ARM_HWCAP_A64_ATOMICS);
8105cfea248SMarielle Novastrider     GET_FEATURE_ID(aa64_lse2, ARM_HWCAP_A64_USCAT);
811962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_rdm, ARM_HWCAP_A64_ASIMDRDM);
812962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_dp, ARM_HWCAP_A64_ASIMDDP);
813962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA);
814cd208a1cSRichard Henderson     GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE);
81529d26ab2SRichard Henderson     GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG);
8161c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM);
8175cfea248SMarielle Novastrider     GET_FEATURE_ID(aa64_dit, ARM_HWCAP_A64_DIT);
8181c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
8199888bd1eSRichard Henderson     GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
820b89d9c98SRichard Henderson     GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
8210d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
8222677cf9fSPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
823a1229109SPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
824962fcbf2SRichard Henderson 
8252041df4aSRichard Henderson     return hwcaps;
8262041df4aSRichard Henderson }
8272041df4aSRichard Henderson 
82863c1b7deSPeter Maydell uint64_t get_elf_hwcap2(void)
8292041df4aSRichard Henderson {
8302041df4aSRichard Henderson     ARMCPU *cpu = ARM_CPU(thread_cpu);
83163c1b7deSPeter Maydell     uint64_t hwcaps = 0;
8322041df4aSRichard Henderson 
8330d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
834cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2, ARM_HWCAP2_A64_SVE2);
835cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_aes, ARM_HWCAP2_A64_SVEAES);
836cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_pmull128, ARM_HWCAP2_A64_SVEPMULL);
837cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_bitperm, ARM_HWCAP2_A64_SVEBITPERM);
838cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sha3, ARM_HWCAP2_A64_SVESHA3);
839cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sm4, ARM_HWCAP2_A64_SVESM4);
8402041df4aSRichard Henderson     GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
8412041df4aSRichard Henderson     GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
842cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_i8mm, ARM_HWCAP2_A64_SVEI8MM);
843cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f32mm, ARM_HWCAP2_A64_SVEF32MM);
844cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f64mm, ARM_HWCAP2_A64_SVEF64MM);
8456c47a905SRichard Henderson     GET_FEATURE_ID(aa64_sve_bf16, ARM_HWCAP2_A64_SVEBF16);
846cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_i8mm, ARM_HWCAP2_A64_I8MM);
8476c47a905SRichard Henderson     GET_FEATURE_ID(aa64_bf16, ARM_HWCAP2_A64_BF16);
84868948d18SRichard Henderson     GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG);
84968948d18SRichard Henderson     GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI);
85068948d18SRichard Henderson     GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE);
8515cfea248SMarielle Novastrider     GET_FEATURE_ID(aa64_mte3, ARM_HWCAP2_A64_MTE3);
852f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme, (ARM_HWCAP2_A64_SME |
853f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F32F32 |
854f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_B16F32 |
855f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F16F32 |
856f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_I8I32));
857f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_f64f64, ARM_HWCAP2_A64_SME_F64F64);
858f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_i16i64, ARM_HWCAP2_A64_SME_I16I64);
859f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_fa64, ARM_HWCAP2_A64_SME_FA64);
8603039b090SPeter Maydell     GET_FEATURE_ID(aa64_hbc, ARM_HWCAP2_A64_HBC);
861706a92fbSPeter Maydell     GET_FEATURE_ID(aa64_mops, ARM_HWCAP2_A64_MOPS);
86224e76ff0SPeter Maydell 
86324e76ff0SPeter Maydell     return hwcaps;
86424e76ff0SPeter Maydell }
86524e76ff0SPeter Maydell 
866a55b9e72SHelge Deller const char *elf_hwcap_str(uint32_t bit)
867a55b9e72SHelge Deller {
868a55b9e72SHelge Deller     static const char *hwcap_str[] = {
869a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FP      )] = "fp",
870a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMD   )] = "asimd",
871a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_EVTSTRM )] = "evtstrm",
872a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_AES     )] = "aes",
873a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PMULL   )] = "pmull",
874a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA1    )] = "sha1",
875a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA2    )] = "sha2",
876a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_CRC32   )] = "crc32",
877a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ATOMICS )] = "atomics",
878a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FPHP    )] = "fphp",
879a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDHP )] = "asimdhp",
880a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_CPUID   )] = "cpuid",
881a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDRDM)] = "asimdrdm",
882a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_JSCVT   )] = "jscvt",
883a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FCMA    )] = "fcma",
884a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_LRCPC   )] = "lrcpc",
885a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_DCPOP   )] = "dcpop",
886a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA3    )] = "sha3",
887a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SM3     )] = "sm3",
888a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SM4     )] = "sm4",
889a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDDP )] = "asimddp",
890a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA512  )] = "sha512",
891a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SVE     )] = "sve",
892a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDFHM)] = "asimdfhm",
893a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_DIT     )] = "dit",
894a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_USCAT   )] = "uscat",
895a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ILRCPC  )] = "ilrcpc",
896a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FLAGM   )] = "flagm",
897a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SSBS    )] = "ssbs",
898a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SB      )] = "sb",
899a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PACA    )] = "paca",
900a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PACG    )] = "pacg",
901a55b9e72SHelge Deller     };
902a55b9e72SHelge Deller 
903a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
904a55b9e72SHelge Deller }
905a55b9e72SHelge Deller 
906a55b9e72SHelge Deller const char *elf_hwcap2_str(uint32_t bit)
907a55b9e72SHelge Deller {
908a55b9e72SHelge Deller     static const char *hwcap_str[] = {
909a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_DCPODP       )] = "dcpodp",
910a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVE2         )] = "sve2",
911a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEAES       )] = "sveaes",
912a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEPMULL     )] = "svepmull",
913a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEBITPERM   )] = "svebitperm",
914a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVESHA3      )] = "svesha3",
915a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVESM4       )] = "svesm4",
916a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_FLAGM2       )] = "flagm2",
917a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_FRINT        )] = "frint",
918a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEI8MM      )] = "svei8mm",
919a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEF32MM     )] = "svef32mm",
920a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEF64MM     )] = "svef64mm",
921a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEBF16      )] = "svebf16",
922a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_I8MM         )] = "i8mm",
923a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_BF16         )] = "bf16",
924a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_DGH          )] = "dgh",
925a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_RNG          )] = "rng",
926a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_BTI          )] = "bti",
927a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_MTE          )] = "mte",
928a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_ECV          )] = "ecv",
929a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_AFP          )] = "afp",
930a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_RPRES        )] = "rpres",
931a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_MTE3         )] = "mte3",
932a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SME          )] = "sme",
933e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_I16I64   )] = "smei16i64",
934e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F64F64   )] = "smef64f64",
935e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_I8I32    )] = "smei8i32",
936e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F16F32   )] = "smef16f32",
937e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_B16F32   )] = "smeb16f32",
938e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F32F32   )] = "smef32f32",
939e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_FA64     )] = "smefa64",
94023d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_WFXT         )] = "wfxt",
94123d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_EBF16      )] = "ebf16",
94223d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SVE_EBF16  )] = "sveebf16",
94323d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_CSSC       )] = "cssc",
94423d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_RPRFM      )] = "rprfm",
94523d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SVE2P1     )] = "sve2p1",
94623d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME2       )] = "sme2",
94723d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME2P1     )] = "sme2p1",
94823d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_I16I32 )] = "smei16i32",
94923d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_BI32I32)] = "smebi32i32",
95023d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_B16B16 )] = "smeb16b16",
95123d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_F16F16 )] = "smef16f16",
95223d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_MOPS       )] = "mops",
95323d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_HBC        )] = "hbc",
954a55b9e72SHelge Deller     };
955a55b9e72SHelge Deller 
956a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
957a55b9e72SHelge Deller }
958a55b9e72SHelge Deller 
9592041df4aSRichard Henderson #undef GET_FEATURE_ID
9602041df4aSRichard Henderson 
96124e76ff0SPeter Maydell #endif /* not TARGET_AARCH64 */
962a9f495b9SRichard Henderson 
963ee95fae0SRichard Henderson #if TARGET_BIG_ENDIAN
964ee95fae0SRichard Henderson # define VDSO_HEADER  "vdso-be.c.inc"
965ee95fae0SRichard Henderson #else
966ee95fae0SRichard Henderson # define VDSO_HEADER  "vdso-le.c.inc"
967ee95fae0SRichard Henderson #endif
968ee95fae0SRichard Henderson 
96924e76ff0SPeter Maydell #endif /* TARGET_ARM */
97030ac07d4Sbellard 
971853d6f7aSbellard #ifdef TARGET_SPARC
972853d6f7aSbellard 
9731cde1a2aSRichard Henderson #ifndef TARGET_SPARC64
974853d6f7aSbellard # define ELF_CLASS  ELFCLASS32
975853d6f7aSbellard # define ELF_ARCH   EM_SPARC
9761cde1a2aSRichard Henderson #elif defined(TARGET_ABI32)
9771cde1a2aSRichard Henderson # define ELF_CLASS  ELFCLASS32
9781cde1a2aSRichard Henderson # define elf_check_arch(x) ((x) == EM_SPARC32PLUS || (x) == EM_SPARC)
9791cde1a2aSRichard Henderson #else
9801cde1a2aSRichard Henderson # define ELF_CLASS  ELFCLASS64
9811cde1a2aSRichard Henderson # define ELF_ARCH   EM_SPARCV9
9821cde1a2aSRichard Henderson #endif
9831cde1a2aSRichard Henderson 
9841cde1a2aSRichard Henderson #include "elf.h"
9851cde1a2aSRichard Henderson 
9861cde1a2aSRichard Henderson #define ELF_HWCAP get_elf_hwcap()
9871cde1a2aSRichard Henderson 
9881cde1a2aSRichard Henderson static uint32_t get_elf_hwcap(void)
9891cde1a2aSRichard Henderson {
9901cde1a2aSRichard Henderson     /* There are not many sparc32 hwcap bits -- we have all of them. */
9911cde1a2aSRichard Henderson     uint32_t r = HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
9921cde1a2aSRichard Henderson                  HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV;
9931cde1a2aSRichard Henderson 
9941cde1a2aSRichard Henderson #ifdef TARGET_SPARC64
9951cde1a2aSRichard Henderson     CPUSPARCState *env = cpu_env(thread_cpu);
9961cde1a2aSRichard Henderson     uint32_t features = env->def.features;
9971cde1a2aSRichard Henderson 
9981cde1a2aSRichard Henderson     r |= HWCAP_SPARC_V9 | HWCAP_SPARC_V8PLUS;
9991cde1a2aSRichard Henderson     /* 32x32 multiply and divide are efficient. */
10001cde1a2aSRichard Henderson     r |= HWCAP_SPARC_MUL32 | HWCAP_SPARC_DIV32;
10011cde1a2aSRichard Henderson     /* We don't have an internal feature bit for this. */
10021cde1a2aSRichard Henderson     r |= HWCAP_SPARC_POPC;
10031cde1a2aSRichard Henderson     r |= features & CPU_FEATURE_FSMULD ? HWCAP_SPARC_FSMULD : 0;
10041cde1a2aSRichard Henderson     r |= features & CPU_FEATURE_VIS1 ? HWCAP_SPARC_VIS : 0;
10051cde1a2aSRichard Henderson     r |= features & CPU_FEATURE_VIS2 ? HWCAP_SPARC_VIS2 : 0;
1006*4fd71d19SRichard Henderson     r |= features & CPU_FEATURE_FMAF ? HWCAP_SPARC_FMAF : 0;
10071cde1a2aSRichard Henderson #endif
10081cde1a2aSRichard Henderson 
10091cde1a2aSRichard Henderson     return r;
10101cde1a2aSRichard Henderson }
1011853d6f7aSbellard 
1012d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1013d97ef72eSRichard Henderson                                struct image_info *infop)
1014853d6f7aSbellard {
1015089a2256SRichard Henderson     /* Note that target_cpu_copy_regs does not read psr/tstate. */
1016f5155289Sbellard     regs->pc = infop->entry;
1017f5155289Sbellard     regs->npc = regs->pc + 4;
1018f5155289Sbellard     regs->y = 0;
1019089a2256SRichard Henderson     regs->u_regs[14] = (infop->start_stack - 16 * sizeof(abi_ulong)
1020089a2256SRichard Henderson                         - TARGET_STACK_BIAS);
1021853d6f7aSbellard }
1022089a2256SRichard Henderson #endif /* TARGET_SPARC */
1023853d6f7aSbellard 
102467867308Sbellard #ifdef TARGET_PPC
102567867308Sbellard 
10264ecd4d16SPeter Crosthwaite #define ELF_MACHINE    PPC_ELF_MACHINE
102767867308Sbellard 
102874154d7eSThomas Huth #if defined(TARGET_PPC64)
102984409ddbSj_mayer 
103084409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
103184409ddbSj_mayer 
103284409ddbSj_mayer #define ELF_CLASS       ELFCLASS64
103384409ddbSj_mayer 
103484409ddbSj_mayer #else
103584409ddbSj_mayer 
103667867308Sbellard #define ELF_CLASS       ELFCLASS32
1037872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
103884409ddbSj_mayer 
103984409ddbSj_mayer #endif
104084409ddbSj_mayer 
104167867308Sbellard #define ELF_ARCH        EM_PPC
104267867308Sbellard 
1043df84e4f3SNathan Froyd /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
1044df84e4f3SNathan Froyd    See arch/powerpc/include/asm/cputable.h.  */
1045df84e4f3SNathan Froyd enum {
10463efa9a67Smalc     QEMU_PPC_FEATURE_32 = 0x80000000,
10473efa9a67Smalc     QEMU_PPC_FEATURE_64 = 0x40000000,
10483efa9a67Smalc     QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
10493efa9a67Smalc     QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
10503efa9a67Smalc     QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
10513efa9a67Smalc     QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
10523efa9a67Smalc     QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
10533efa9a67Smalc     QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
10543efa9a67Smalc     QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
10553efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
10563efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
10573efa9a67Smalc     QEMU_PPC_FEATURE_NO_TB = 0x00100000,
10583efa9a67Smalc     QEMU_PPC_FEATURE_POWER4 = 0x00080000,
10593efa9a67Smalc     QEMU_PPC_FEATURE_POWER5 = 0x00040000,
10603efa9a67Smalc     QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
10613efa9a67Smalc     QEMU_PPC_FEATURE_CELL = 0x00010000,
10623efa9a67Smalc     QEMU_PPC_FEATURE_BOOKE = 0x00008000,
10633efa9a67Smalc     QEMU_PPC_FEATURE_SMT = 0x00004000,
10643efa9a67Smalc     QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
10653efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
10663efa9a67Smalc     QEMU_PPC_FEATURE_PA6T = 0x00000800,
10673efa9a67Smalc     QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
10683efa9a67Smalc     QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
10693efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
10703efa9a67Smalc     QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
10713efa9a67Smalc     QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
1072df84e4f3SNathan Froyd 
10733efa9a67Smalc     QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
10743efa9a67Smalc     QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
1075a60438ddSTom Musta 
1076a60438ddSTom Musta     /* Feature definitions in AT_HWCAP2.  */
1077a60438ddSTom Musta     QEMU_PPC_FEATURE2_ARCH_2_07 = 0x80000000, /* ISA 2.07 */
1078a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_HTM = 0x40000000, /* Hardware Transactional Memory */
1079a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_DSCR = 0x20000000, /* Data Stream Control Register */
1080a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */
1081a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */
1082a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */
108324c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_VEC_CRYPTO = 0x02000000,
108424c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NOSC = 0x01000000,
1085be0c46d4SSandipan Das     QEMU_PPC_FEATURE2_ARCH_3_00 = 0x00800000, /* ISA 3.00 */
108624c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HAS_IEEE128 = 0x00400000, /* VSX IEEE Bin Float 128-bit */
108724c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */
108824c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */
108924c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */
109096c343ccSJoel Stanley     QEMU_PPC_FEATURE2_ARCH_3_1 = 0x00040000, /* ISA 3.1 */
109196c343ccSJoel Stanley     QEMU_PPC_FEATURE2_MMA = 0x00020000, /* Matrix-Multiply Assist */
1092df84e4f3SNathan Froyd };
1093df84e4f3SNathan Froyd 
1094df84e4f3SNathan Froyd #define ELF_HWCAP get_elf_hwcap()
1095df84e4f3SNathan Froyd 
1096df84e4f3SNathan Froyd static uint32_t get_elf_hwcap(void)
1097df84e4f3SNathan Froyd {
1098a2247f8eSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
1099df84e4f3SNathan Froyd     uint32_t features = 0;
1100df84e4f3SNathan Froyd 
1101df84e4f3SNathan Froyd     /* We don't have to be terribly complete here; the high points are
1102df84e4f3SNathan Froyd        Altivec/FP/SPE support.  Anything else is just a bonus.  */
1103df84e4f3SNathan Froyd #define GET_FEATURE(flag, feature)                                      \
1104a2247f8eSAndreas Färber     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
110558eb5308SMichael Walle #define GET_FEATURE2(flags, feature) \
110658eb5308SMichael Walle     do { \
110758eb5308SMichael Walle         if ((cpu->env.insns_flags2 & flags) == flags) { \
110858eb5308SMichael Walle             features |= feature; \
110958eb5308SMichael Walle         } \
111058eb5308SMichael Walle     } while (0)
11113efa9a67Smalc     GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
11123efa9a67Smalc     GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
11133efa9a67Smalc     GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
11143efa9a67Smalc     GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
11153efa9a67Smalc     GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
11163efa9a67Smalc     GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
11173efa9a67Smalc     GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
11183efa9a67Smalc     GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
11190e019746STom Musta     GET_FEATURE2(PPC2_DFP, QEMU_PPC_FEATURE_HAS_DFP);
11200e019746STom Musta     GET_FEATURE2(PPC2_VSX, QEMU_PPC_FEATURE_HAS_VSX);
11210e019746STom Musta     GET_FEATURE2((PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 |
11220e019746STom Musta                   PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206),
11230e019746STom Musta                   QEMU_PPC_FEATURE_ARCH_2_06);
1124df84e4f3SNathan Froyd #undef GET_FEATURE
11250e019746STom Musta #undef GET_FEATURE2
1126df84e4f3SNathan Froyd 
1127df84e4f3SNathan Froyd     return features;
1128df84e4f3SNathan Froyd }
1129df84e4f3SNathan Froyd 
1130a60438ddSTom Musta #define ELF_HWCAP2 get_elf_hwcap2()
1131a60438ddSTom Musta 
1132a60438ddSTom Musta static uint32_t get_elf_hwcap2(void)
1133a60438ddSTom Musta {
1134a60438ddSTom Musta     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
1135a60438ddSTom Musta     uint32_t features = 0;
1136a60438ddSTom Musta 
1137a60438ddSTom Musta #define GET_FEATURE(flag, feature)                                      \
1138a60438ddSTom Musta     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
1139a60438ddSTom Musta #define GET_FEATURE2(flag, feature)                                      \
1140a60438ddSTom Musta     do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
1141a60438ddSTom Musta 
1142a60438ddSTom Musta     GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL);
1143a60438ddSTom Musta     GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR);
1144a60438ddSTom Musta     GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
114524c373ecSLaurent Vivier                   PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07 |
114624c373ecSLaurent Vivier                   QEMU_PPC_FEATURE2_VEC_CRYPTO);
114724c373ecSLaurent Vivier     GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 |
11488a589aebSKhem Raj                  QEMU_PPC_FEATURE2_DARN | QEMU_PPC_FEATURE2_HAS_IEEE128);
114996c343ccSJoel Stanley     GET_FEATURE2(PPC2_ISA310, QEMU_PPC_FEATURE2_ARCH_3_1 |
115096c343ccSJoel Stanley                  QEMU_PPC_FEATURE2_MMA);
1151a60438ddSTom Musta 
1152a60438ddSTom Musta #undef GET_FEATURE
1153a60438ddSTom Musta #undef GET_FEATURE2
1154a60438ddSTom Musta 
1155a60438ddSTom Musta     return features;
1156a60438ddSTom Musta }
1157a60438ddSTom Musta 
1158f5155289Sbellard /*
1159f5155289Sbellard  * The requirements here are:
1160f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
1161f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
1162f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
1163f5155289Sbellard  *   AT_IGNOREPPC is used for that.
1164f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
1165f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
1166f5155289Sbellard  */
11670bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
1168f5155289Sbellard #define ARCH_DLINFO                                     \
1169f5155289Sbellard     do {                                                \
1170623e250aSTom Musta         PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);              \
1171f5155289Sbellard         /*                                              \
117282991bedSPeter Maydell          * Handle glibc compatibility: these magic entries must \
117382991bedSPeter Maydell          * be at the lowest addresses in the final auxv.        \
1174f5155289Sbellard          */                                             \
11750bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
11760bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
117782991bedSPeter Maydell         NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
117882991bedSPeter Maydell         NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
117982991bedSPeter Maydell         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                 \
1180f5155289Sbellard     } while (0)
1181f5155289Sbellard 
118267867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
118367867308Sbellard {
118467867308Sbellard     _regs->gpr[1] = infop->start_stack;
118574154d7eSThomas Huth #if defined(TARGET_PPC64)
1186d90b94cdSDoug Kwan     if (get_ppc64_abi(infop) < 2) {
11872ccf97ecSPeter Maydell         uint64_t val;
11882ccf97ecSPeter Maydell         get_user_u64(val, infop->entry + 8);
11892ccf97ecSPeter Maydell         _regs->gpr[2] = val + infop->load_bias;
11902ccf97ecSPeter Maydell         get_user_u64(val, infop->entry);
11912ccf97ecSPeter Maydell         infop->entry = val + infop->load_bias;
1192d90b94cdSDoug Kwan     } else {
1193d90b94cdSDoug Kwan         _regs->gpr[12] = infop->entry;  /* r12 set to global entry address */
1194d90b94cdSDoug Kwan     }
119584409ddbSj_mayer #endif
119667867308Sbellard     _regs->nip = infop->entry;
119767867308Sbellard }
119867867308Sbellard 
1199e2f3e741SNathan Froyd /* See linux kernel: arch/powerpc/include/asm/elf.h.  */
1200e2f3e741SNathan Froyd #define ELF_NREG 48
1201e2f3e741SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1202e2f3e741SNathan Froyd 
120305390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *env)
1204e2f3e741SNathan Froyd {
1205e2f3e741SNathan Froyd     int i;
1206e2f3e741SNathan Froyd     target_ulong ccr = 0;
1207e2f3e741SNathan Froyd 
1208e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
120986cd7b2dSPaolo Bonzini         (*regs)[i] = tswapreg(env->gpr[i]);
1210e2f3e741SNathan Froyd     }
1211e2f3e741SNathan Froyd 
121286cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->nip);
121386cd7b2dSPaolo Bonzini     (*regs)[33] = tswapreg(env->msr);
121486cd7b2dSPaolo Bonzini     (*regs)[35] = tswapreg(env->ctr);
121586cd7b2dSPaolo Bonzini     (*regs)[36] = tswapreg(env->lr);
121610de0521SMatheus Ferst     (*regs)[37] = tswapreg(cpu_read_xer(env));
1217e2f3e741SNathan Froyd 
12182060436aSHarsh Prateek Bora     ccr = ppc_get_cr(env);
121986cd7b2dSPaolo Bonzini     (*regs)[38] = tswapreg(ccr);
1220e2f3e741SNathan Froyd }
1221e2f3e741SNathan Froyd 
1222e2f3e741SNathan Froyd #define USE_ELF_CORE_DUMP
122367867308Sbellard #define ELF_EXEC_PAGESIZE       4096
122467867308Sbellard 
1225e34136d9SRichard Henderson #ifndef TARGET_PPC64
1226e34136d9SRichard Henderson # define VDSO_HEADER  "vdso-32.c.inc"
1227e34136d9SRichard Henderson #elif TARGET_BIG_ENDIAN
1228e34136d9SRichard Henderson # define VDSO_HEADER  "vdso-64.c.inc"
1229e34136d9SRichard Henderson #else
1230e34136d9SRichard Henderson # define VDSO_HEADER  "vdso-64le.c.inc"
1231e34136d9SRichard Henderson #endif
1232e34136d9SRichard Henderson 
123367867308Sbellard #endif
123467867308Sbellard 
12353418fe25SSong Gao #ifdef TARGET_LOONGARCH64
12363418fe25SSong Gao 
12373418fe25SSong Gao #define ELF_CLASS   ELFCLASS64
12383418fe25SSong Gao #define ELF_ARCH    EM_LOONGARCH
1239872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
12403418fe25SSong Gao 
12413418fe25SSong Gao #define elf_check_arch(x) ((x) == EM_LOONGARCH)
12423418fe25SSong Gao 
124300cc2934SRichard Henderson #define VDSO_HEADER "vdso.c.inc"
124400cc2934SRichard Henderson 
12453418fe25SSong Gao static inline void init_thread(struct target_pt_regs *regs,
12463418fe25SSong Gao                                struct image_info *infop)
12473418fe25SSong Gao {
12483418fe25SSong Gao     /*Set crmd PG,DA = 1,0 */
12493418fe25SSong Gao     regs->csr.crmd = 2 << 3;
12503418fe25SSong Gao     regs->csr.era = infop->entry;
12513418fe25SSong Gao     regs->regs[3] = infop->start_stack;
12523418fe25SSong Gao }
12533418fe25SSong Gao 
12543418fe25SSong Gao /* See linux kernel: arch/loongarch/include/asm/elf.h */
12553418fe25SSong Gao #define ELF_NREG 45
12563418fe25SSong Gao typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
12573418fe25SSong Gao 
12583418fe25SSong Gao enum {
12593418fe25SSong Gao     TARGET_EF_R0 = 0,
12603418fe25SSong Gao     TARGET_EF_CSR_ERA = TARGET_EF_R0 + 33,
12613418fe25SSong Gao     TARGET_EF_CSR_BADV = TARGET_EF_R0 + 34,
12623418fe25SSong Gao };
12633418fe25SSong Gao 
12643418fe25SSong Gao static void elf_core_copy_regs(target_elf_gregset_t *regs,
12653418fe25SSong Gao                                const CPULoongArchState *env)
12663418fe25SSong Gao {
12673418fe25SSong Gao     int i;
12683418fe25SSong Gao 
12693418fe25SSong Gao     (*regs)[TARGET_EF_R0] = 0;
12703418fe25SSong Gao 
12713418fe25SSong Gao     for (i = 1; i < ARRAY_SIZE(env->gpr); i++) {
12723418fe25SSong Gao         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->gpr[i]);
12733418fe25SSong Gao     }
12743418fe25SSong Gao 
12753418fe25SSong Gao     (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->pc);
12763418fe25SSong Gao     (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV);
12773418fe25SSong Gao }
12783418fe25SSong Gao 
12793418fe25SSong Gao #define USE_ELF_CORE_DUMP
12803418fe25SSong Gao #define ELF_EXEC_PAGESIZE        4096
12813418fe25SSong Gao 
12823418fe25SSong Gao #define ELF_HWCAP get_elf_hwcap()
12833418fe25SSong Gao 
12843418fe25SSong Gao /* See arch/loongarch/include/uapi/asm/hwcap.h */
12853418fe25SSong Gao enum {
12863418fe25SSong Gao     HWCAP_LOONGARCH_CPUCFG   = (1 << 0),
12873418fe25SSong Gao     HWCAP_LOONGARCH_LAM      = (1 << 1),
12883418fe25SSong Gao     HWCAP_LOONGARCH_UAL      = (1 << 2),
12893418fe25SSong Gao     HWCAP_LOONGARCH_FPU      = (1 << 3),
12903418fe25SSong Gao     HWCAP_LOONGARCH_LSX      = (1 << 4),
12913418fe25SSong Gao     HWCAP_LOONGARCH_LASX     = (1 << 5),
12923418fe25SSong Gao     HWCAP_LOONGARCH_CRC32    = (1 << 6),
12933418fe25SSong Gao     HWCAP_LOONGARCH_COMPLEX  = (1 << 7),
12943418fe25SSong Gao     HWCAP_LOONGARCH_CRYPTO   = (1 << 8),
12953418fe25SSong Gao     HWCAP_LOONGARCH_LVZ      = (1 << 9),
12963418fe25SSong Gao     HWCAP_LOONGARCH_LBT_X86  = (1 << 10),
12973418fe25SSong Gao     HWCAP_LOONGARCH_LBT_ARM  = (1 << 11),
12983418fe25SSong Gao     HWCAP_LOONGARCH_LBT_MIPS = (1 << 12),
12993418fe25SSong Gao };
13003418fe25SSong Gao 
13013418fe25SSong Gao static uint32_t get_elf_hwcap(void)
13023418fe25SSong Gao {
13033418fe25SSong Gao     LoongArchCPU *cpu = LOONGARCH_CPU(thread_cpu);
13043418fe25SSong Gao     uint32_t hwcaps = 0;
13053418fe25SSong Gao 
13063418fe25SSong Gao     hwcaps |= HWCAP_LOONGARCH_CRC32;
13073418fe25SSong Gao 
13083418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[1], CPUCFG1, UAL)) {
13093418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_UAL;
13103418fe25SSong Gao     }
13113418fe25SSong Gao 
13123418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, FP)) {
13133418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_FPU;
13143418fe25SSong Gao     }
13153418fe25SSong Gao 
13163418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LAM)) {
13173418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_LAM;
13183418fe25SSong Gao     }
13193418fe25SSong Gao 
1320a9f6004fSJiajie Chen     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
1321a9f6004fSJiajie Chen         hwcaps |= HWCAP_LOONGARCH_LSX;
1322a9f6004fSJiajie Chen     }
1323a9f6004fSJiajie Chen 
1324a9f6004fSJiajie Chen     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) {
1325a9f6004fSJiajie Chen         hwcaps |= HWCAP_LOONGARCH_LASX;
1326a9f6004fSJiajie Chen     }
1327a9f6004fSJiajie Chen 
13283418fe25SSong Gao     return hwcaps;
13293418fe25SSong Gao }
13303418fe25SSong Gao 
13313418fe25SSong Gao #define ELF_PLATFORM "loongarch"
13323418fe25SSong Gao 
13333418fe25SSong Gao #endif /* TARGET_LOONGARCH64 */
13343418fe25SSong Gao 
1335048f6b4dSbellard #ifdef TARGET_MIPS
1336048f6b4dSbellard 
1337388bb21aSths #ifdef TARGET_MIPS64
1338388bb21aSths #define ELF_CLASS   ELFCLASS64
1339388bb21aSths #else
1340048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
1341388bb21aSths #endif
1342048f6b4dSbellard #define ELF_ARCH    EM_MIPS
1343872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
1344048f6b4dSbellard 
1345ace3d654SCarlo Marcelo Arenas Belón #ifdef TARGET_ABI_MIPSN32
1346ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) ((x) & EF_MIPS_ABI2)
1347ace3d654SCarlo Marcelo Arenas Belón #else
1348ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (!((x) & EF_MIPS_ABI2))
1349ace3d654SCarlo Marcelo Arenas Belón #endif
1350ace3d654SCarlo Marcelo Arenas Belón 
1351fbf47c18SJiaxun Yang #define ELF_BASE_PLATFORM get_elf_base_platform()
1352fbf47c18SJiaxun Yang 
1353fbf47c18SJiaxun Yang #define MATCH_PLATFORM_INSN(_flags, _base_platform)      \
1354fbf47c18SJiaxun Yang     do { if ((cpu->env.insn_flags & (_flags)) == _flags) \
1355fbf47c18SJiaxun Yang     { return _base_platform; } } while (0)
1356fbf47c18SJiaxun Yang 
1357fbf47c18SJiaxun Yang static const char *get_elf_base_platform(void)
1358fbf47c18SJiaxun Yang {
1359fbf47c18SJiaxun Yang     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
1360fbf47c18SJiaxun Yang 
1361fbf47c18SJiaxun Yang     /* 64 bit ISAs goes first */
1362fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R6, "mips64r6");
1363fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R5, "mips64r5");
1364fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R2, "mips64r2");
1365fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R1, "mips64");
1366fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS5, "mips5");
1367fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS4, "mips4");
1368fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS3, "mips3");
1369fbf47c18SJiaxun Yang 
1370fbf47c18SJiaxun Yang     /* 32 bit ISAs */
1371fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R6, "mips32r6");
1372fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R5, "mips32r5");
1373fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R2, "mips32r2");
1374fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R1, "mips32");
1375fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS2, "mips2");
1376fbf47c18SJiaxun Yang 
1377fbf47c18SJiaxun Yang     /* Fallback */
1378fbf47c18SJiaxun Yang     return "mips";
1379fbf47c18SJiaxun Yang }
1380fbf47c18SJiaxun Yang #undef MATCH_PLATFORM_INSN
1381fbf47c18SJiaxun Yang 
1382d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1383d97ef72eSRichard Henderson                                struct image_info *infop)
1384048f6b4dSbellard {
1385623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
1386048f6b4dSbellard     regs->cp0_epc = infop->entry;
1387048f6b4dSbellard     regs->regs[29] = infop->start_stack;
1388048f6b4dSbellard }
1389048f6b4dSbellard 
139051e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/elf.h.  */
139151e52606SNathan Froyd #define ELF_NREG 45
139251e52606SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
139351e52606SNathan Froyd 
139451e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/reg.h.  */
139551e52606SNathan Froyd enum {
139651e52606SNathan Froyd #ifdef TARGET_MIPS64
139751e52606SNathan Froyd     TARGET_EF_R0 = 0,
139851e52606SNathan Froyd #else
139951e52606SNathan Froyd     TARGET_EF_R0 = 6,
140051e52606SNathan Froyd #endif
140151e52606SNathan Froyd     TARGET_EF_R26 = TARGET_EF_R0 + 26,
140251e52606SNathan Froyd     TARGET_EF_R27 = TARGET_EF_R0 + 27,
140351e52606SNathan Froyd     TARGET_EF_LO = TARGET_EF_R0 + 32,
140451e52606SNathan Froyd     TARGET_EF_HI = TARGET_EF_R0 + 33,
140551e52606SNathan Froyd     TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
140651e52606SNathan Froyd     TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
140751e52606SNathan Froyd     TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
140851e52606SNathan Froyd     TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
140951e52606SNathan Froyd };
141051e52606SNathan Froyd 
141151e52606SNathan Froyd /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
141205390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMIPSState *env)
141351e52606SNathan Froyd {
141451e52606SNathan Froyd     int i;
141551e52606SNathan Froyd 
141651e52606SNathan Froyd     for (i = 0; i < TARGET_EF_R0; i++) {
141751e52606SNathan Froyd         (*regs)[i] = 0;
141851e52606SNathan Froyd     }
141951e52606SNathan Froyd     (*regs)[TARGET_EF_R0] = 0;
142051e52606SNathan Froyd 
142151e52606SNathan Froyd     for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
1422a29f998dSPaolo Bonzini         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]);
142351e52606SNathan Froyd     }
142451e52606SNathan Froyd 
142551e52606SNathan Froyd     (*regs)[TARGET_EF_R26] = 0;
142651e52606SNathan Froyd     (*regs)[TARGET_EF_R27] = 0;
1427a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_LO] = tswapreg(env->active_tc.LO[0]);
1428a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_HI] = tswapreg(env->active_tc.HI[0]);
1429a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_EPC] = tswapreg(env->active_tc.PC);
1430a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_BADVADDR] = tswapreg(env->CP0_BadVAddr);
1431a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_STATUS] = tswapreg(env->CP0_Status);
1432a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_CAUSE] = tswapreg(env->CP0_Cause);
143351e52606SNathan Froyd }
143451e52606SNathan Froyd 
143551e52606SNathan Froyd #define USE_ELF_CORE_DUMP
1436388bb21aSths #define ELF_EXEC_PAGESIZE        4096
1437388bb21aSths 
143846a1ee4fSJames Cowgill /* See arch/mips/include/uapi/asm/hwcap.h.  */
143946a1ee4fSJames Cowgill enum {
144046a1ee4fSJames Cowgill     HWCAP_MIPS_R6           = (1 << 0),
144146a1ee4fSJames Cowgill     HWCAP_MIPS_MSA          = (1 << 1),
14429ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_CRC32        = (1 << 2),
14439ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16       = (1 << 3),
14449ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MDMX         = (1 << 4),
14459ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS3D       = (1 << 5),
14469ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_SMARTMIPS    = (1 << 6),
14479ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP          = (1 << 7),
14489ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP2         = (1 << 8),
14499ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP3         = (1 << 9),
14509ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16E2     = (1 << 10),
14519ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_MMI      = (1 << 11),
14529ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT      = (1 << 12),
14539ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT2     = (1 << 13),
14549ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_CPUCFG   = (1 << 14),
145546a1ee4fSJames Cowgill };
145646a1ee4fSJames Cowgill 
145746a1ee4fSJames Cowgill #define ELF_HWCAP get_elf_hwcap()
145846a1ee4fSJames Cowgill 
14597d9a3d96SPhilippe Mathieu-Daudé #define GET_FEATURE_INSN(_flag, _hwcap) \
14606dd97bfcSPhilippe Mathieu-Daudé     do { if (cpu->env.insn_flags & (_flag)) { hwcaps |= _hwcap; } } while (0)
14616dd97bfcSPhilippe Mathieu-Daudé 
1462388765a0SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_SET(_reg, _mask, _hwcap) \
1463388765a0SPhilippe Mathieu-Daudé     do { if (cpu->env._reg & (_mask)) { hwcaps |= _hwcap; } } while (0)
1464388765a0SPhilippe Mathieu-Daudé 
1465ce543844SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_EQU(_reg, _start, _length, _val, _hwcap) \
1466ce543844SPhilippe Mathieu-Daudé     do { \
1467ce543844SPhilippe Mathieu-Daudé         if (extract32(cpu->env._reg, (_start), (_length)) == (_val)) { \
1468ce543844SPhilippe Mathieu-Daudé             hwcaps |= _hwcap; \
1469ce543844SPhilippe Mathieu-Daudé         } \
1470ce543844SPhilippe Mathieu-Daudé     } while (0)
1471ce543844SPhilippe Mathieu-Daudé 
147246a1ee4fSJames Cowgill static uint32_t get_elf_hwcap(void)
147346a1ee4fSJames Cowgill {
147446a1ee4fSJames Cowgill     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
147546a1ee4fSJames Cowgill     uint32_t hwcaps = 0;
147646a1ee4fSJames Cowgill 
1477ce543844SPhilippe Mathieu-Daudé     GET_FEATURE_REG_EQU(CP0_Config0, CP0C0_AR, CP0C0_AR_LENGTH,
1478ce543844SPhilippe Mathieu-Daudé                         2, HWCAP_MIPS_R6);
1479388765a0SPhilippe Mathieu-Daudé     GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA);
148053673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LMMI, HWCAP_LOONGSON_MMI);
148153673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LEXT, HWCAP_LOONGSON_EXT);
148246a1ee4fSJames Cowgill 
148346a1ee4fSJames Cowgill     return hwcaps;
148446a1ee4fSJames Cowgill }
148546a1ee4fSJames Cowgill 
1486ce543844SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_EQU
1487388765a0SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_SET
14887d9a3d96SPhilippe Mathieu-Daudé #undef GET_FEATURE_INSN
14896dd97bfcSPhilippe Mathieu-Daudé 
1490048f6b4dSbellard #endif /* TARGET_MIPS */
1491048f6b4dSbellard 
1492b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
1493b779e29eSEdgar E. Iglesias 
14940d5d4699SEdgar E. Iglesias #define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
1495b779e29eSEdgar E. Iglesias 
1496b779e29eSEdgar E. Iglesias #define ELF_CLASS   ELFCLASS32
14970d5d4699SEdgar E. Iglesias #define ELF_ARCH    EM_MICROBLAZE
1498b779e29eSEdgar E. Iglesias 
1499d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1500d97ef72eSRichard Henderson                                struct image_info *infop)
1501b779e29eSEdgar E. Iglesias {
1502b779e29eSEdgar E. Iglesias     regs->pc = infop->entry;
1503b779e29eSEdgar E. Iglesias     regs->r1 = infop->start_stack;
1504b779e29eSEdgar E. Iglesias 
1505b779e29eSEdgar E. Iglesias }
1506b779e29eSEdgar E. Iglesias 
1507b779e29eSEdgar E. Iglesias #define ELF_EXEC_PAGESIZE        4096
1508b779e29eSEdgar E. Iglesias 
1509e4cbd44dSEdgar E. Iglesias #define USE_ELF_CORE_DUMP
1510e4cbd44dSEdgar E. Iglesias #define ELF_NREG 38
1511e4cbd44dSEdgar E. Iglesias typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1512e4cbd44dSEdgar E. Iglesias 
1513e4cbd44dSEdgar E. Iglesias /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
151405390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env)
1515e4cbd44dSEdgar E. Iglesias {
1516e4cbd44dSEdgar E. Iglesias     int i, pos = 0;
1517e4cbd44dSEdgar E. Iglesias 
1518e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 32; i++) {
151986cd7b2dSPaolo Bonzini         (*regs)[pos++] = tswapreg(env->regs[i]);
1520e4cbd44dSEdgar E. Iglesias     }
1521e4cbd44dSEdgar E. Iglesias 
1522af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->pc);
15231074c0fbSRichard Henderson     (*regs)[pos++] = tswapreg(mb_cpu_read_msr(env));
1524af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1525af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->ear);
1526af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1527af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->esr);
1528e4cbd44dSEdgar E. Iglesias }
1529e4cbd44dSEdgar E. Iglesias 
1530b779e29eSEdgar E. Iglesias #endif /* TARGET_MICROBLAZE */
1531b779e29eSEdgar E. Iglesias 
1532d962783eSJia Liu #ifdef TARGET_OPENRISC
1533d962783eSJia Liu 
1534d962783eSJia Liu #define ELF_ARCH EM_OPENRISC
1535d962783eSJia Liu #define ELF_CLASS ELFCLASS32
1536d962783eSJia Liu #define ELF_DATA  ELFDATA2MSB
1537d962783eSJia Liu 
1538d962783eSJia Liu static inline void init_thread(struct target_pt_regs *regs,
1539d962783eSJia Liu                                struct image_info *infop)
1540d962783eSJia Liu {
1541d962783eSJia Liu     regs->pc = infop->entry;
1542d962783eSJia Liu     regs->gpr[1] = infop->start_stack;
1543d962783eSJia Liu }
1544d962783eSJia Liu 
1545d962783eSJia Liu #define USE_ELF_CORE_DUMP
1546d962783eSJia Liu #define ELF_EXEC_PAGESIZE 8192
1547d962783eSJia Liu 
1548d962783eSJia Liu /* See linux kernel arch/openrisc/include/asm/elf.h.  */
1549d962783eSJia Liu #define ELF_NREG 34 /* gprs and pc, sr */
1550d962783eSJia Liu typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1551d962783eSJia Liu 
1552d962783eSJia Liu static void elf_core_copy_regs(target_elf_gregset_t *regs,
1553d962783eSJia Liu                                const CPUOpenRISCState *env)
1554d962783eSJia Liu {
1555d962783eSJia Liu     int i;
1556d962783eSJia Liu 
1557d962783eSJia Liu     for (i = 0; i < 32; i++) {
1558d89e71e8SStafford Horne         (*regs)[i] = tswapreg(cpu_get_gpr(env, i));
1559d962783eSJia Liu     }
156086cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->pc);
156184775c43SRichard Henderson     (*regs)[33] = tswapreg(cpu_get_sr(env));
1562d962783eSJia Liu }
1563d962783eSJia Liu #define ELF_HWCAP 0
1564d962783eSJia Liu #define ELF_PLATFORM NULL
1565d962783eSJia Liu 
1566d962783eSJia Liu #endif /* TARGET_OPENRISC */
1567d962783eSJia Liu 
1568fdf9b3e8Sbellard #ifdef TARGET_SH4
1569fdf9b3e8Sbellard 
1570fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
1571fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
1572fdf9b3e8Sbellard 
1573d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1574d97ef72eSRichard Henderson                                struct image_info *infop)
1575fdf9b3e8Sbellard {
1576fdf9b3e8Sbellard     /* Check other registers XXXXX */
1577fdf9b3e8Sbellard     regs->pc = infop->entry;
1578072ae847Sths     regs->regs[15] = infop->start_stack;
1579fdf9b3e8Sbellard }
1580fdf9b3e8Sbellard 
15817631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/elf.h.  */
15827631c97eSNathan Froyd #define ELF_NREG 23
15837631c97eSNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
15847631c97eSNathan Froyd 
15857631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/ptrace.h.  */
15867631c97eSNathan Froyd enum {
15877631c97eSNathan Froyd     TARGET_REG_PC = 16,
15887631c97eSNathan Froyd     TARGET_REG_PR = 17,
15897631c97eSNathan Froyd     TARGET_REG_SR = 18,
15907631c97eSNathan Froyd     TARGET_REG_GBR = 19,
15917631c97eSNathan Froyd     TARGET_REG_MACH = 20,
15927631c97eSNathan Froyd     TARGET_REG_MACL = 21,
15937631c97eSNathan Froyd     TARGET_REG_SYSCALL = 22
15947631c97eSNathan Froyd };
15957631c97eSNathan Froyd 
1596d97ef72eSRichard Henderson static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
159705390248SAndreas Färber                                       const CPUSH4State *env)
15987631c97eSNathan Froyd {
15997631c97eSNathan Froyd     int i;
16007631c97eSNathan Froyd 
16017631c97eSNathan Froyd     for (i = 0; i < 16; i++) {
160272cd500bSPhilippe Mathieu-Daudé         (*regs)[i] = tswapreg(env->gregs[i]);
16037631c97eSNathan Froyd     }
16047631c97eSNathan Froyd 
160586cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
160686cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PR] = tswapreg(env->pr);
160786cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_SR] = tswapreg(env->sr);
160886cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_GBR] = tswapreg(env->gbr);
160986cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACH] = tswapreg(env->mach);
161086cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACL] = tswapreg(env->macl);
16117631c97eSNathan Froyd     (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
16127631c97eSNathan Froyd }
16137631c97eSNathan Froyd 
16147631c97eSNathan Froyd #define USE_ELF_CORE_DUMP
1615fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
1616fdf9b3e8Sbellard 
1617e42fd944SRichard Henderson enum {
1618e42fd944SRichard Henderson     SH_CPU_HAS_FPU            = 0x0001, /* Hardware FPU support */
1619e42fd944SRichard Henderson     SH_CPU_HAS_P2_FLUSH_BUG   = 0x0002, /* Need to flush the cache in P2 area */
1620e42fd944SRichard Henderson     SH_CPU_HAS_MMU_PAGE_ASSOC = 0x0004, /* SH3: TLB way selection bit support */
1621e42fd944SRichard Henderson     SH_CPU_HAS_DSP            = 0x0008, /* SH-DSP: DSP support */
1622e42fd944SRichard Henderson     SH_CPU_HAS_PERF_COUNTER   = 0x0010, /* Hardware performance counters */
1623e42fd944SRichard Henderson     SH_CPU_HAS_PTEA           = 0x0020, /* PTEA register */
1624e42fd944SRichard Henderson     SH_CPU_HAS_LLSC           = 0x0040, /* movli.l/movco.l */
1625e42fd944SRichard Henderson     SH_CPU_HAS_L2_CACHE       = 0x0080, /* Secondary cache / URAM */
1626e42fd944SRichard Henderson     SH_CPU_HAS_OP32           = 0x0100, /* 32-bit instruction support */
1627e42fd944SRichard Henderson     SH_CPU_HAS_PTEAEX         = 0x0200, /* PTE ASID Extension support */
1628e42fd944SRichard Henderson };
1629e42fd944SRichard Henderson 
1630e42fd944SRichard Henderson #define ELF_HWCAP get_elf_hwcap()
1631e42fd944SRichard Henderson 
1632e42fd944SRichard Henderson static uint32_t get_elf_hwcap(void)
1633e42fd944SRichard Henderson {
1634e42fd944SRichard Henderson     SuperHCPU *cpu = SUPERH_CPU(thread_cpu);
1635e42fd944SRichard Henderson     uint32_t hwcap = 0;
1636e42fd944SRichard Henderson 
1637e42fd944SRichard Henderson     hwcap |= SH_CPU_HAS_FPU;
1638e42fd944SRichard Henderson 
1639e42fd944SRichard Henderson     if (cpu->env.features & SH_FEATURE_SH4A) {
1640e42fd944SRichard Henderson         hwcap |= SH_CPU_HAS_LLSC;
1641e42fd944SRichard Henderson     }
1642e42fd944SRichard Henderson 
1643e42fd944SRichard Henderson     return hwcap;
1644e42fd944SRichard Henderson }
1645e42fd944SRichard Henderson 
1646fdf9b3e8Sbellard #endif
1647fdf9b3e8Sbellard 
164848733d19Sths #ifdef TARGET_CRIS
164948733d19Sths 
165048733d19Sths #define ELF_CLASS ELFCLASS32
165148733d19Sths #define ELF_ARCH  EM_CRIS
165248733d19Sths 
1653d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1654d97ef72eSRichard Henderson                                struct image_info *infop)
165548733d19Sths {
165648733d19Sths     regs->erp = infop->entry;
165748733d19Sths }
165848733d19Sths 
165948733d19Sths #define ELF_EXEC_PAGESIZE        8192
166048733d19Sths 
166148733d19Sths #endif
166248733d19Sths 
1663e6e5906bSpbrook #ifdef TARGET_M68K
1664e6e5906bSpbrook 
1665e6e5906bSpbrook #define ELF_CLASS       ELFCLASS32
1666e6e5906bSpbrook #define ELF_ARCH        EM_68K
1667e6e5906bSpbrook 
1668e6e5906bSpbrook /* ??? Does this need to do anything?
1669e6e5906bSpbrook    #define ELF_PLAT_INIT(_r) */
1670e6e5906bSpbrook 
1671d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1672d97ef72eSRichard Henderson                                struct image_info *infop)
1673e6e5906bSpbrook {
1674e6e5906bSpbrook     regs->usp = infop->start_stack;
1675e6e5906bSpbrook     regs->sr = 0;
1676e6e5906bSpbrook     regs->pc = infop->entry;
1677e6e5906bSpbrook }
1678e6e5906bSpbrook 
16797a93cc55SNathan Froyd /* See linux kernel: arch/m68k/include/asm/elf.h.  */
16807a93cc55SNathan Froyd #define ELF_NREG 20
16817a93cc55SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
16827a93cc55SNathan Froyd 
168305390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUM68KState *env)
16847a93cc55SNathan Froyd {
168586cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->dregs[1]);
168686cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->dregs[2]);
168786cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->dregs[3]);
168886cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->dregs[4]);
168986cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->dregs[5]);
169086cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->dregs[6]);
169186cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->dregs[7]);
169286cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->aregs[0]);
169386cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->aregs[1]);
169486cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->aregs[2]);
169586cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->aregs[3]);
169686cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->aregs[4]);
169786cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->aregs[5]);
169886cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->aregs[6]);
169986cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->dregs[0]);
170086cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->aregs[7]);
170186cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(env->dregs[0]); /* FIXME: orig_d0 */
170286cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->sr);
170386cd7b2dSPaolo Bonzini     (*regs)[18] = tswapreg(env->pc);
17047a93cc55SNathan Froyd     (*regs)[19] = 0;  /* FIXME: regs->format | regs->vector */
17057a93cc55SNathan Froyd }
17067a93cc55SNathan Froyd 
17077a93cc55SNathan Froyd #define USE_ELF_CORE_DUMP
1708e6e5906bSpbrook #define ELF_EXEC_PAGESIZE       8192
1709e6e5906bSpbrook 
1710e6e5906bSpbrook #endif
1711e6e5906bSpbrook 
17127a3148a9Sj_mayer #ifdef TARGET_ALPHA
17137a3148a9Sj_mayer 
17147a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
17157a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
17167a3148a9Sj_mayer 
1717d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1718d97ef72eSRichard Henderson                                struct image_info *infop)
17197a3148a9Sj_mayer {
17207a3148a9Sj_mayer     regs->pc = infop->entry;
17217a3148a9Sj_mayer     regs->ps = 8;
17227a3148a9Sj_mayer     regs->usp = infop->start_stack;
17237a3148a9Sj_mayer }
17247a3148a9Sj_mayer 
17257a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
17267a3148a9Sj_mayer 
17277a3148a9Sj_mayer #endif /* TARGET_ALPHA */
17287a3148a9Sj_mayer 
1729a4c075f1SUlrich Hecht #ifdef TARGET_S390X
1730a4c075f1SUlrich Hecht 
1731a4c075f1SUlrich Hecht #define ELF_CLASS	ELFCLASS64
1732a4c075f1SUlrich Hecht #define ELF_DATA	ELFDATA2MSB
1733a4c075f1SUlrich Hecht #define ELF_ARCH	EM_S390
1734a4c075f1SUlrich Hecht 
17356d88baf1SDavid Hildenbrand #include "elf.h"
17366d88baf1SDavid Hildenbrand 
17376d88baf1SDavid Hildenbrand #define ELF_HWCAP get_elf_hwcap()
17386d88baf1SDavid Hildenbrand 
17396d88baf1SDavid Hildenbrand #define GET_FEATURE(_feat, _hwcap) \
17406d88baf1SDavid Hildenbrand     do { if (s390_has_feat(_feat)) { hwcap |= _hwcap; } } while (0)
17416d88baf1SDavid Hildenbrand 
1742e1b819c8SIlya Leoshkevich uint32_t get_elf_hwcap(void)
17436d88baf1SDavid Hildenbrand {
17446d88baf1SDavid Hildenbrand     /*
17456d88baf1SDavid Hildenbrand      * Let's assume we always have esan3 and zarch.
17466d88baf1SDavid Hildenbrand      * 31-bit processes can use 64-bit registers (high gprs).
17476d88baf1SDavid Hildenbrand      */
17486d88baf1SDavid Hildenbrand     uint32_t hwcap = HWCAP_S390_ESAN3 | HWCAP_S390_ZARCH | HWCAP_S390_HIGH_GPRS;
17496d88baf1SDavid Hildenbrand 
17506d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_STFLE, HWCAP_S390_STFLE);
17516d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_MSA, HWCAP_S390_MSA);
17526d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_LONG_DISPLACEMENT, HWCAP_S390_LDISP);
17536d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_EXTENDED_IMMEDIATE, HWCAP_S390_EIMM);
17546d88baf1SDavid Hildenbrand     if (s390_has_feat(S390_FEAT_EXTENDED_TRANSLATION_3) &&
17556d88baf1SDavid Hildenbrand         s390_has_feat(S390_FEAT_ETF3_ENH)) {
17566d88baf1SDavid Hildenbrand         hwcap |= HWCAP_S390_ETF3EH;
17576d88baf1SDavid Hildenbrand     }
17586d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS);
1759da215c23SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR_ENH, HWCAP_S390_VXRS_EXT);
1760ffc8453bSIlya Leoshkevich     GET_FEATURE(S390_FEAT_VECTOR_ENH2, HWCAP_S390_VXRS_EXT2);
17616d88baf1SDavid Hildenbrand 
17626d88baf1SDavid Hildenbrand     return hwcap;
17636d88baf1SDavid Hildenbrand }
17646d88baf1SDavid Hildenbrand 
1765e19807beSIlya Leoshkevich const char *elf_hwcap_str(uint32_t bit)
1766e19807beSIlya Leoshkevich {
1767e19807beSIlya Leoshkevich     static const char *hwcap_str[] = {
17687f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ESAN3]     = "esan3",
17697f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ZARCH]     = "zarch",
17707f114a58SIlya Leoshkevich         [HWCAP_S390_NR_STFLE]     = "stfle",
17717f114a58SIlya Leoshkevich         [HWCAP_S390_NR_MSA]       = "msa",
17727f114a58SIlya Leoshkevich         [HWCAP_S390_NR_LDISP]     = "ldisp",
17737f114a58SIlya Leoshkevich         [HWCAP_S390_NR_EIMM]      = "eimm",
17747f114a58SIlya Leoshkevich         [HWCAP_S390_NR_DFP]       = "dfp",
17757f114a58SIlya Leoshkevich         [HWCAP_S390_NR_HPAGE]     = "edat",
17767f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ETF3EH]    = "etf3eh",
17777f114a58SIlya Leoshkevich         [HWCAP_S390_NR_HIGH_GPRS] = "highgprs",
17787f114a58SIlya Leoshkevich         [HWCAP_S390_NR_TE]        = "te",
17797f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS]      = "vx",
17807f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_BCD]  = "vxd",
17817f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_EXT]  = "vxe",
17827f114a58SIlya Leoshkevich         [HWCAP_S390_NR_GS]        = "gs",
17837f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_EXT2] = "vxe2",
17847f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_PDE]  = "vxp",
17857f114a58SIlya Leoshkevich         [HWCAP_S390_NR_SORT]      = "sort",
17867f114a58SIlya Leoshkevich         [HWCAP_S390_NR_DFLT]      = "dflt",
17877f114a58SIlya Leoshkevich         [HWCAP_S390_NR_NNPA]      = "nnpa",
17887f114a58SIlya Leoshkevich         [HWCAP_S390_NR_PCI_MIO]   = "pcimio",
17897f114a58SIlya Leoshkevich         [HWCAP_S390_NR_SIE]       = "sie",
1790e19807beSIlya Leoshkevich     };
1791e19807beSIlya Leoshkevich 
1792e19807beSIlya Leoshkevich     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
1793e19807beSIlya Leoshkevich }
1794e19807beSIlya Leoshkevich 
1795a4c075f1SUlrich Hecht static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1796a4c075f1SUlrich Hecht {
1797a4c075f1SUlrich Hecht     regs->psw.addr = infop->entry;
179878a1e153SIlya Leoshkevich     regs->psw.mask = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | \
179978a1e153SIlya Leoshkevich                      PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_MASK_64 | \
180078a1e153SIlya Leoshkevich                      PSW_MASK_32;
1801a4c075f1SUlrich Hecht     regs->gprs[15] = infop->start_stack;
1802a4c075f1SUlrich Hecht }
1803a4c075f1SUlrich Hecht 
18044a1e8931SIlya Leoshkevich /* See linux kernel: arch/s390/include/uapi/asm/ptrace.h (s390_regs).  */
18054a1e8931SIlya Leoshkevich #define ELF_NREG 27
18064a1e8931SIlya Leoshkevich typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
18074a1e8931SIlya Leoshkevich 
18084a1e8931SIlya Leoshkevich enum {
18094a1e8931SIlya Leoshkevich     TARGET_REG_PSWM = 0,
18104a1e8931SIlya Leoshkevich     TARGET_REG_PSWA = 1,
18114a1e8931SIlya Leoshkevich     TARGET_REG_GPRS = 2,
18124a1e8931SIlya Leoshkevich     TARGET_REG_ARS = 18,
18134a1e8931SIlya Leoshkevich     TARGET_REG_ORIG_R2 = 26,
18144a1e8931SIlya Leoshkevich };
18154a1e8931SIlya Leoshkevich 
18164a1e8931SIlya Leoshkevich static void elf_core_copy_regs(target_elf_gregset_t *regs,
18174a1e8931SIlya Leoshkevich                                const CPUS390XState *env)
18184a1e8931SIlya Leoshkevich {
18194a1e8931SIlya Leoshkevich     int i;
18204a1e8931SIlya Leoshkevich     uint32_t *aregs;
18214a1e8931SIlya Leoshkevich 
18224a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWM] = tswapreg(env->psw.mask);
18234a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWA] = tswapreg(env->psw.addr);
18244a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
18254a1e8931SIlya Leoshkevich         (*regs)[TARGET_REG_GPRS + i] = tswapreg(env->regs[i]);
18264a1e8931SIlya Leoshkevich     }
18274a1e8931SIlya Leoshkevich     aregs = (uint32_t *)&((*regs)[TARGET_REG_ARS]);
18284a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
18294a1e8931SIlya Leoshkevich         aregs[i] = tswap32(env->aregs[i]);
18304a1e8931SIlya Leoshkevich     }
18314a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_ORIG_R2] = 0;
18324a1e8931SIlya Leoshkevich }
18334a1e8931SIlya Leoshkevich 
18344a1e8931SIlya Leoshkevich #define USE_ELF_CORE_DUMP
18354a1e8931SIlya Leoshkevich #define ELF_EXEC_PAGESIZE 4096
18364a1e8931SIlya Leoshkevich 
1837b63c6b97SRichard Henderson #define VDSO_HEADER "vdso.c.inc"
1838b63c6b97SRichard Henderson 
1839a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
1840a4c075f1SUlrich Hecht 
184147ae93cdSMichael Clark #ifdef TARGET_RISCV
184247ae93cdSMichael Clark 
184347ae93cdSMichael Clark #define ELF_ARCH  EM_RISCV
184447ae93cdSMichael Clark 
184547ae93cdSMichael Clark #ifdef TARGET_RISCV32
184647ae93cdSMichael Clark #define ELF_CLASS ELFCLASS32
1847468c1bb5SRichard Henderson #define VDSO_HEADER "vdso-32.c.inc"
184847ae93cdSMichael Clark #else
184947ae93cdSMichael Clark #define ELF_CLASS ELFCLASS64
1850468c1bb5SRichard Henderson #define VDSO_HEADER "vdso-64.c.inc"
185147ae93cdSMichael Clark #endif
185247ae93cdSMichael Clark 
1853cb46938cSKito Cheng #define ELF_HWCAP get_elf_hwcap()
1854cb46938cSKito Cheng 
1855cb46938cSKito Cheng static uint32_t get_elf_hwcap(void)
1856cb46938cSKito Cheng {
1857cb46938cSKito Cheng #define MISA_BIT(EXT) (1 << (EXT - 'A'))
1858cb46938cSKito Cheng     RISCVCPU *cpu = RISCV_CPU(thread_cpu);
1859cb46938cSKito Cheng     uint32_t mask = MISA_BIT('I') | MISA_BIT('M') | MISA_BIT('A')
18604333f092SNathan Egge                     | MISA_BIT('F') | MISA_BIT('D') | MISA_BIT('C')
18614333f092SNathan Egge                     | MISA_BIT('V');
1862cb46938cSKito Cheng 
1863e91a7227SRichard Henderson     return cpu->env.misa_ext & mask;
1864cb46938cSKito Cheng #undef MISA_BIT
1865cb46938cSKito Cheng }
1866cb46938cSKito Cheng 
186747ae93cdSMichael Clark static inline void init_thread(struct target_pt_regs *regs,
186847ae93cdSMichael Clark                                struct image_info *infop)
186947ae93cdSMichael Clark {
187047ae93cdSMichael Clark     regs->sepc = infop->entry;
187147ae93cdSMichael Clark     regs->sp = infop->start_stack;
187247ae93cdSMichael Clark }
187347ae93cdSMichael Clark 
187447ae93cdSMichael Clark #define ELF_EXEC_PAGESIZE 4096
187547ae93cdSMichael Clark 
187647ae93cdSMichael Clark #endif /* TARGET_RISCV */
187747ae93cdSMichael Clark 
18787c248bcdSRichard Henderson #ifdef TARGET_HPPA
18797c248bcdSRichard Henderson 
18807c248bcdSRichard Henderson #define ELF_CLASS       ELFCLASS32
18817c248bcdSRichard Henderson #define ELF_ARCH        EM_PARISC
18827c248bcdSRichard Henderson #define ELF_PLATFORM    "PARISC"
18837c248bcdSRichard Henderson #define STACK_GROWS_DOWN 0
18847c248bcdSRichard Henderson #define STACK_ALIGNMENT  64
18857c248bcdSRichard Henderson 
1886c7bc2a8fSRichard Henderson #define VDSO_HEADER "vdso.c.inc"
1887c7bc2a8fSRichard Henderson 
18887c248bcdSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
18897c248bcdSRichard Henderson                                struct image_info *infop)
18907c248bcdSRichard Henderson {
18913c13b0ffSRichard Henderson     regs->iaoq[0] = infop->entry | PRIV_USER;
18923c13b0ffSRichard Henderson     regs->iaoq[1] = regs->iaoq[0] + 4;
18937c248bcdSRichard Henderson     regs->gr[23] = 0;
189460f1c801SRichard Henderson     regs->gr[24] = infop->argv;
189560f1c801SRichard Henderson     regs->gr[25] = infop->argc;
18967c248bcdSRichard Henderson     /* The top-of-stack contains a linkage buffer.  */
18977c248bcdSRichard Henderson     regs->gr[30] = infop->start_stack + 64;
18987c248bcdSRichard Henderson     regs->gr[31] = infop->entry;
18997c248bcdSRichard Henderson }
19007c248bcdSRichard Henderson 
1901eee816c0SRichard Henderson #define LO_COMMPAGE  0
1902eee816c0SRichard Henderson 
1903eee816c0SRichard Henderson static bool init_guest_commpage(void)
1904eee816c0SRichard Henderson {
1905d1fc6230SRichard Henderson     /* If reserved_va, then we have already mapped 0 page on the host. */
1906d1fc6230SRichard Henderson     if (!reserved_va) {
1907d1fc6230SRichard Henderson         void *want, *addr;
1908eee816c0SRichard Henderson 
1909d1fc6230SRichard Henderson         want = g2h_untagged(LO_COMMPAGE);
1910d1fc6230SRichard Henderson         addr = mmap(want, TARGET_PAGE_SIZE, PROT_NONE,
1911d1fc6230SRichard Henderson                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0);
1912eee816c0SRichard Henderson         if (addr == MAP_FAILED) {
1913eee816c0SRichard Henderson             perror("Allocating guest commpage");
1914eee816c0SRichard Henderson             exit(EXIT_FAILURE);
1915eee816c0SRichard Henderson         }
1916eee816c0SRichard Henderson         if (addr != want) {
1917eee816c0SRichard Henderson             return false;
1918eee816c0SRichard Henderson         }
1919d1fc6230SRichard Henderson     }
1920eee816c0SRichard Henderson 
1921eee816c0SRichard Henderson     /*
1922eee816c0SRichard Henderson      * On Linux, page zero is normally marked execute only + gateway.
1923eee816c0SRichard Henderson      * Normal read or write is supposed to fail (thus PROT_NONE above),
1924eee816c0SRichard Henderson      * but specific offsets have kernel code mapped to raise permissions
1925eee816c0SRichard Henderson      * and implement syscalls.  Here, simply mark the page executable.
1926eee816c0SRichard Henderson      * Special case the entry points during translation (see do_page_zero).
1927eee816c0SRichard Henderson      */
192849840a4aSRichard Henderson     page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
1929eee816c0SRichard Henderson                    PAGE_EXEC | PAGE_VALID);
1930eee816c0SRichard Henderson     return true;
1931eee816c0SRichard Henderson }
1932eee816c0SRichard Henderson 
19337c248bcdSRichard Henderson #endif /* TARGET_HPPA */
19347c248bcdSRichard Henderson 
1935ba7651fbSMax Filippov #ifdef TARGET_XTENSA
1936ba7651fbSMax Filippov 
1937ba7651fbSMax Filippov #define ELF_CLASS       ELFCLASS32
1938ba7651fbSMax Filippov #define ELF_ARCH        EM_XTENSA
1939ba7651fbSMax Filippov 
1940ba7651fbSMax Filippov static inline void init_thread(struct target_pt_regs *regs,
1941ba7651fbSMax Filippov                                struct image_info *infop)
1942ba7651fbSMax Filippov {
1943ba7651fbSMax Filippov     regs->windowbase = 0;
1944ba7651fbSMax Filippov     regs->windowstart = 1;
1945ba7651fbSMax Filippov     regs->areg[1] = infop->start_stack;
1946ba7651fbSMax Filippov     regs->pc = infop->entry;
1947d2796be6SMax Filippov     if (info_is_fdpic(infop)) {
1948d2796be6SMax Filippov         regs->areg[4] = infop->loadmap_addr;
1949d2796be6SMax Filippov         regs->areg[5] = infop->interpreter_loadmap_addr;
1950d2796be6SMax Filippov         if (infop->interpreter_loadmap_addr) {
1951d2796be6SMax Filippov             regs->areg[6] = infop->interpreter_pt_dynamic_addr;
1952d2796be6SMax Filippov         } else {
1953d2796be6SMax Filippov             regs->areg[6] = infop->pt_dynamic_addr;
1954d2796be6SMax Filippov         }
1955d2796be6SMax Filippov     }
1956ba7651fbSMax Filippov }
1957ba7651fbSMax Filippov 
1958ba7651fbSMax Filippov /* See linux kernel: arch/xtensa/include/asm/elf.h.  */
1959ba7651fbSMax Filippov #define ELF_NREG 128
1960ba7651fbSMax Filippov typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1961ba7651fbSMax Filippov 
1962ba7651fbSMax Filippov enum {
1963ba7651fbSMax Filippov     TARGET_REG_PC,
1964ba7651fbSMax Filippov     TARGET_REG_PS,
1965ba7651fbSMax Filippov     TARGET_REG_LBEG,
1966ba7651fbSMax Filippov     TARGET_REG_LEND,
1967ba7651fbSMax Filippov     TARGET_REG_LCOUNT,
1968ba7651fbSMax Filippov     TARGET_REG_SAR,
1969ba7651fbSMax Filippov     TARGET_REG_WINDOWSTART,
1970ba7651fbSMax Filippov     TARGET_REG_WINDOWBASE,
1971ba7651fbSMax Filippov     TARGET_REG_THREADPTR,
1972ba7651fbSMax Filippov     TARGET_REG_AR0 = 64,
1973ba7651fbSMax Filippov };
1974ba7651fbSMax Filippov 
1975ba7651fbSMax Filippov static void elf_core_copy_regs(target_elf_gregset_t *regs,
1976ba7651fbSMax Filippov                                const CPUXtensaState *env)
1977ba7651fbSMax Filippov {
1978ba7651fbSMax Filippov     unsigned i;
1979ba7651fbSMax Filippov 
1980ba7651fbSMax Filippov     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
1981ba7651fbSMax Filippov     (*regs)[TARGET_REG_PS] = tswapreg(env->sregs[PS] & ~PS_EXCM);
1982ba7651fbSMax Filippov     (*regs)[TARGET_REG_LBEG] = tswapreg(env->sregs[LBEG]);
1983ba7651fbSMax Filippov     (*regs)[TARGET_REG_LEND] = tswapreg(env->sregs[LEND]);
1984ba7651fbSMax Filippov     (*regs)[TARGET_REG_LCOUNT] = tswapreg(env->sregs[LCOUNT]);
1985ba7651fbSMax Filippov     (*regs)[TARGET_REG_SAR] = tswapreg(env->sregs[SAR]);
1986ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWSTART] = tswapreg(env->sregs[WINDOW_START]);
1987ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWBASE] = tswapreg(env->sregs[WINDOW_BASE]);
1988ba7651fbSMax Filippov     (*regs)[TARGET_REG_THREADPTR] = tswapreg(env->uregs[THREADPTR]);
1989ba7651fbSMax Filippov     xtensa_sync_phys_from_window((CPUXtensaState *)env);
1990ba7651fbSMax Filippov     for (i = 0; i < env->config->nareg; ++i) {
1991ba7651fbSMax Filippov         (*regs)[TARGET_REG_AR0 + i] = tswapreg(env->phys_regs[i]);
1992ba7651fbSMax Filippov     }
1993ba7651fbSMax Filippov }
1994ba7651fbSMax Filippov 
1995ba7651fbSMax Filippov #define USE_ELF_CORE_DUMP
1996ba7651fbSMax Filippov #define ELF_EXEC_PAGESIZE       4096
1997ba7651fbSMax Filippov 
1998ba7651fbSMax Filippov #endif /* TARGET_XTENSA */
1999ba7651fbSMax Filippov 
2000d2a56bd2STaylor Simpson #ifdef TARGET_HEXAGON
2001d2a56bd2STaylor Simpson 
2002d2a56bd2STaylor Simpson #define ELF_CLASS       ELFCLASS32
2003d2a56bd2STaylor Simpson #define ELF_ARCH        EM_HEXAGON
2004d2a56bd2STaylor Simpson 
2005d2a56bd2STaylor Simpson static inline void init_thread(struct target_pt_regs *regs,
2006d2a56bd2STaylor Simpson                                struct image_info *infop)
2007d2a56bd2STaylor Simpson {
2008d2a56bd2STaylor Simpson     regs->sepc = infop->entry;
2009d2a56bd2STaylor Simpson     regs->sp = infop->start_stack;
2010d2a56bd2STaylor Simpson }
2011d2a56bd2STaylor Simpson 
2012d2a56bd2STaylor Simpson #endif /* TARGET_HEXAGON */
2013d2a56bd2STaylor Simpson 
2014fcdc0ab4SJiaxun Yang #ifndef ELF_BASE_PLATFORM
2015fcdc0ab4SJiaxun Yang #define ELF_BASE_PLATFORM (NULL)
2016fcdc0ab4SJiaxun Yang #endif
2017fcdc0ab4SJiaxun Yang 
201815338fd7Sbellard #ifndef ELF_PLATFORM
201915338fd7Sbellard #define ELF_PLATFORM (NULL)
202015338fd7Sbellard #endif
202115338fd7Sbellard 
202275be901cSPeter Crosthwaite #ifndef ELF_MACHINE
202375be901cSPeter Crosthwaite #define ELF_MACHINE ELF_ARCH
202475be901cSPeter Crosthwaite #endif
202575be901cSPeter Crosthwaite 
2026d276a604SPeter Crosthwaite #ifndef elf_check_arch
2027d276a604SPeter Crosthwaite #define elf_check_arch(x) ((x) == ELF_ARCH)
2028d276a604SPeter Crosthwaite #endif
2029d276a604SPeter Crosthwaite 
2030ace3d654SCarlo Marcelo Arenas Belón #ifndef elf_check_abi
2031ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (1)
2032ace3d654SCarlo Marcelo Arenas Belón #endif
2033ace3d654SCarlo Marcelo Arenas Belón 
203415338fd7Sbellard #ifndef ELF_HWCAP
203515338fd7Sbellard #define ELF_HWCAP 0
203615338fd7Sbellard #endif
203715338fd7Sbellard 
20387c4ee5bcSRichard Henderson #ifndef STACK_GROWS_DOWN
20397c4ee5bcSRichard Henderson #define STACK_GROWS_DOWN 1
20407c4ee5bcSRichard Henderson #endif
20417c4ee5bcSRichard Henderson 
20427c4ee5bcSRichard Henderson #ifndef STACK_ALIGNMENT
20437c4ee5bcSRichard Henderson #define STACK_ALIGNMENT 16
20447c4ee5bcSRichard Henderson #endif
20457c4ee5bcSRichard Henderson 
2046992f48a0Sblueswir1 #ifdef TARGET_ABI32
2047cb33da57Sblueswir1 #undef ELF_CLASS
2048992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
2049cb33da57Sblueswir1 #undef bswaptls
2050cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
2051cb33da57Sblueswir1 #endif
2052cb33da57Sblueswir1 
2053872f3d04SRichard Henderson #ifndef EXSTACK_DEFAULT
2054872f3d04SRichard Henderson #define EXSTACK_DEFAULT false
2055872f3d04SRichard Henderson #endif
2056872f3d04SRichard Henderson 
205731e31b8aSbellard #include "elf.h"
205809bfb054Sbellard 
2059e8384b37SRichard Henderson /* We must delay the following stanzas until after "elf.h". */
2060e8384b37SRichard Henderson #if defined(TARGET_AARCH64)
2061e8384b37SRichard Henderson 
2062e8384b37SRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
2063e8384b37SRichard Henderson                                     const uint32_t *data,
2064e8384b37SRichard Henderson                                     struct image_info *info,
2065e8384b37SRichard Henderson                                     Error **errp)
2066e8384b37SRichard Henderson {
2067e8384b37SRichard Henderson     if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
2068e8384b37SRichard Henderson         if (pr_datasz != sizeof(uint32_t)) {
2069e8384b37SRichard Henderson             error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
2070e8384b37SRichard Henderson             return false;
2071e8384b37SRichard Henderson         }
2072e8384b37SRichard Henderson         /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
2073e8384b37SRichard Henderson         info->note_flags = *data;
2074e8384b37SRichard Henderson     }
2075e8384b37SRichard Henderson     return true;
2076e8384b37SRichard Henderson }
2077e8384b37SRichard Henderson #define ARCH_USE_GNU_PROPERTY 1
2078e8384b37SRichard Henderson 
2079e8384b37SRichard Henderson #else
2080e8384b37SRichard Henderson 
208183f990ebSRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
208283f990ebSRichard Henderson                                     const uint32_t *data,
208383f990ebSRichard Henderson                                     struct image_info *info,
208483f990ebSRichard Henderson                                     Error **errp)
208583f990ebSRichard Henderson {
208683f990ebSRichard Henderson     g_assert_not_reached();
208783f990ebSRichard Henderson }
208883f990ebSRichard Henderson #define ARCH_USE_GNU_PROPERTY 0
208983f990ebSRichard Henderson 
2090e8384b37SRichard Henderson #endif
2091e8384b37SRichard Henderson 
209209bfb054Sbellard struct exec
209309bfb054Sbellard {
209409bfb054Sbellard     unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
209509bfb054Sbellard     unsigned int a_text;   /* length of text, in bytes */
209609bfb054Sbellard     unsigned int a_data;   /* length of data, in bytes */
209709bfb054Sbellard     unsigned int a_bss;    /* length of uninitialized data area, in bytes */
209809bfb054Sbellard     unsigned int a_syms;   /* length of symbol table data in file, in bytes */
209909bfb054Sbellard     unsigned int a_entry;  /* start address */
210009bfb054Sbellard     unsigned int a_trsize; /* length of relocation info for text, in bytes */
210109bfb054Sbellard     unsigned int a_drsize; /* length of relocation info for data, in bytes */
210209bfb054Sbellard };
210309bfb054Sbellard 
210409bfb054Sbellard 
210509bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
210609bfb054Sbellard #define OMAGIC 0407
210709bfb054Sbellard #define NMAGIC 0410
210809bfb054Sbellard #define ZMAGIC 0413
210909bfb054Sbellard #define QMAGIC 0314
211009bfb054Sbellard 
2111e0d1673dSLirong Yuan #define DLINFO_ITEMS 16
211231e31b8aSbellard 
211309bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
211409bfb054Sbellard {
211509bfb054Sbellard     memcpy(to, from, n);
211609bfb054Sbellard }
211709bfb054Sbellard 
211831e31b8aSbellard #ifdef BSWAP_NEEDED
211992a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
212031e31b8aSbellard {
212131e31b8aSbellard     bswap16s(&ehdr->e_type);            /* Object file type */
212231e31b8aSbellard     bswap16s(&ehdr->e_machine);         /* Architecture */
212331e31b8aSbellard     bswap32s(&ehdr->e_version);         /* Object file version */
212492a31b1fSbellard     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
212592a31b1fSbellard     bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
212692a31b1fSbellard     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
212731e31b8aSbellard     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
212831e31b8aSbellard     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
212931e31b8aSbellard     bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
213031e31b8aSbellard     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
213131e31b8aSbellard     bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
213231e31b8aSbellard     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
213331e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
213431e31b8aSbellard }
213531e31b8aSbellard 
2136991f8f0cSRichard Henderson static void bswap_phdr(struct elf_phdr *phdr, int phnum)
213731e31b8aSbellard {
2138991f8f0cSRichard Henderson     int i;
2139991f8f0cSRichard Henderson     for (i = 0; i < phnum; ++i, ++phdr) {
214031e31b8aSbellard         bswap32s(&phdr->p_type);        /* Segment type */
2141991f8f0cSRichard Henderson         bswap32s(&phdr->p_flags);       /* Segment flags */
214292a31b1fSbellard         bswaptls(&phdr->p_offset);      /* Segment file offset */
214392a31b1fSbellard         bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
214492a31b1fSbellard         bswaptls(&phdr->p_paddr);       /* Segment physical address */
214592a31b1fSbellard         bswaptls(&phdr->p_filesz);      /* Segment size in file */
214692a31b1fSbellard         bswaptls(&phdr->p_memsz);       /* Segment size in memory */
214792a31b1fSbellard         bswaptls(&phdr->p_align);       /* Segment alignment */
214831e31b8aSbellard     }
2149991f8f0cSRichard Henderson }
2150689f936fSbellard 
2151991f8f0cSRichard Henderson static void bswap_shdr(struct elf_shdr *shdr, int shnum)
2152689f936fSbellard {
2153991f8f0cSRichard Henderson     int i;
2154991f8f0cSRichard Henderson     for (i = 0; i < shnum; ++i, ++shdr) {
2155689f936fSbellard         bswap32s(&shdr->sh_name);
2156689f936fSbellard         bswap32s(&shdr->sh_type);
215792a31b1fSbellard         bswaptls(&shdr->sh_flags);
215892a31b1fSbellard         bswaptls(&shdr->sh_addr);
215992a31b1fSbellard         bswaptls(&shdr->sh_offset);
216092a31b1fSbellard         bswaptls(&shdr->sh_size);
2161689f936fSbellard         bswap32s(&shdr->sh_link);
2162689f936fSbellard         bswap32s(&shdr->sh_info);
216392a31b1fSbellard         bswaptls(&shdr->sh_addralign);
216492a31b1fSbellard         bswaptls(&shdr->sh_entsize);
2165689f936fSbellard     }
2166991f8f0cSRichard Henderson }
2167689f936fSbellard 
21687a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
2169689f936fSbellard {
2170689f936fSbellard     bswap32s(&sym->st_name);
21717a3148a9Sj_mayer     bswaptls(&sym->st_value);
21727a3148a9Sj_mayer     bswaptls(&sym->st_size);
2173689f936fSbellard     bswap16s(&sym->st_shndx);
2174689f936fSbellard }
21755dd0db52SStefan Markovic 
21765dd0db52SStefan Markovic #ifdef TARGET_MIPS
21775dd0db52SStefan Markovic static void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags)
21785dd0db52SStefan Markovic {
21795dd0db52SStefan Markovic     bswap16s(&abiflags->version);
21805dd0db52SStefan Markovic     bswap32s(&abiflags->ases);
21815dd0db52SStefan Markovic     bswap32s(&abiflags->isa_ext);
21825dd0db52SStefan Markovic     bswap32s(&abiflags->flags1);
21835dd0db52SStefan Markovic     bswap32s(&abiflags->flags2);
21845dd0db52SStefan Markovic }
21855dd0db52SStefan Markovic #endif
2186991f8f0cSRichard Henderson #else
2187991f8f0cSRichard Henderson static inline void bswap_ehdr(struct elfhdr *ehdr) { }
2188991f8f0cSRichard Henderson static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
2189991f8f0cSRichard Henderson static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
2190991f8f0cSRichard Henderson static inline void bswap_sym(struct elf_sym *sym) { }
21915dd0db52SStefan Markovic #ifdef TARGET_MIPS
21925dd0db52SStefan Markovic static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { }
21935dd0db52SStefan Markovic #endif
219431e31b8aSbellard #endif
219531e31b8aSbellard 
2196edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
21979349b4f9SAndreas Färber static int elf_core_dump(int, const CPUArchState *);
2198edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
219986cf82dcSRichard Henderson static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
220086cf82dcSRichard Henderson                          abi_ulong load_bias);
2201edf8e2afSMika Westerberg 
22029058abddSRichard Henderson /* Verify the portions of EHDR within E_IDENT for the target.
22039058abddSRichard Henderson    This can be performed before bswapping the entire header.  */
22049058abddSRichard Henderson static bool elf_check_ident(struct elfhdr *ehdr)
22059058abddSRichard Henderson {
22069058abddSRichard Henderson     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
22079058abddSRichard Henderson             && ehdr->e_ident[EI_MAG1] == ELFMAG1
22089058abddSRichard Henderson             && ehdr->e_ident[EI_MAG2] == ELFMAG2
22099058abddSRichard Henderson             && ehdr->e_ident[EI_MAG3] == ELFMAG3
22109058abddSRichard Henderson             && ehdr->e_ident[EI_CLASS] == ELF_CLASS
22119058abddSRichard Henderson             && ehdr->e_ident[EI_DATA] == ELF_DATA
22129058abddSRichard Henderson             && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
22139058abddSRichard Henderson }
22149058abddSRichard Henderson 
22159058abddSRichard Henderson /* Verify the portions of EHDR outside of E_IDENT for the target.
22169058abddSRichard Henderson    This has to wait until after bswapping the header.  */
22179058abddSRichard Henderson static bool elf_check_ehdr(struct elfhdr *ehdr)
22189058abddSRichard Henderson {
22199058abddSRichard Henderson     return (elf_check_arch(ehdr->e_machine)
2220ace3d654SCarlo Marcelo Arenas Belón             && elf_check_abi(ehdr->e_flags)
22219058abddSRichard Henderson             && ehdr->e_ehsize == sizeof(struct elfhdr)
22229058abddSRichard Henderson             && ehdr->e_phentsize == sizeof(struct elf_phdr)
22239058abddSRichard Henderson             && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
22249058abddSRichard Henderson }
22259058abddSRichard Henderson 
222631e31b8aSbellard /*
2227e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
222831e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
222931e31b8aSbellard  * to be put directly into the top of new user memory.
223031e31b8aSbellard  *
223131e31b8aSbellard  */
223259baae9aSStefan Brüns static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch,
223359baae9aSStefan Brüns                                   abi_ulong p, abi_ulong stack_limit)
223431e31b8aSbellard {
223559baae9aSStefan Brüns     char *tmp;
22367c4ee5bcSRichard Henderson     int len, i;
223759baae9aSStefan Brüns     abi_ulong top = p;
223831e31b8aSbellard 
223931e31b8aSbellard     if (!p) {
224031e31b8aSbellard         return 0;       /* bullet-proofing */
224131e31b8aSbellard     }
224259baae9aSStefan Brüns 
22437c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
22447c4ee5bcSRichard Henderson         int offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
22457c4ee5bcSRichard Henderson         for (i = argc - 1; i >= 0; --i) {
22467c4ee5bcSRichard Henderson             tmp = argv[i];
2247edf779ffSbellard             if (!tmp) {
224831e31b8aSbellard                 fprintf(stderr, "VFS: argc is wrong");
224931e31b8aSbellard                 exit(-1);
225031e31b8aSbellard             }
225159baae9aSStefan Brüns             len = strlen(tmp) + 1;
225259baae9aSStefan Brüns             tmp += len;
225359baae9aSStefan Brüns 
225459baae9aSStefan Brüns             if (len > (p - stack_limit)) {
225531e31b8aSbellard                 return 0;
225631e31b8aSbellard             }
225731e31b8aSbellard             while (len) {
225831e31b8aSbellard                 int bytes_to_copy = (len > offset) ? offset : len;
225931e31b8aSbellard                 tmp -= bytes_to_copy;
226031e31b8aSbellard                 p -= bytes_to_copy;
226131e31b8aSbellard                 offset -= bytes_to_copy;
226231e31b8aSbellard                 len -= bytes_to_copy;
226359baae9aSStefan Brüns 
226459baae9aSStefan Brüns                 memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
226559baae9aSStefan Brüns 
226659baae9aSStefan Brüns                 if (offset == 0) {
226759baae9aSStefan Brüns                     memcpy_to_target(p, scratch, top - p);
226859baae9aSStefan Brüns                     top = p;
226959baae9aSStefan Brüns                     offset = TARGET_PAGE_SIZE;
227031e31b8aSbellard                 }
227131e31b8aSbellard             }
227231e31b8aSbellard         }
22737c4ee5bcSRichard Henderson         if (p != top) {
227459baae9aSStefan Brüns             memcpy_to_target(p, scratch + offset, top - p);
227559baae9aSStefan Brüns         }
22767c4ee5bcSRichard Henderson     } else {
22777c4ee5bcSRichard Henderson         int remaining = TARGET_PAGE_SIZE - (p % TARGET_PAGE_SIZE);
22787c4ee5bcSRichard Henderson         for (i = 0; i < argc; ++i) {
22797c4ee5bcSRichard Henderson             tmp = argv[i];
22807c4ee5bcSRichard Henderson             if (!tmp) {
22817c4ee5bcSRichard Henderson                 fprintf(stderr, "VFS: argc is wrong");
22827c4ee5bcSRichard Henderson                 exit(-1);
22837c4ee5bcSRichard Henderson             }
22847c4ee5bcSRichard Henderson             len = strlen(tmp) + 1;
22857c4ee5bcSRichard Henderson             if (len > (stack_limit - p)) {
22867c4ee5bcSRichard Henderson                 return 0;
22877c4ee5bcSRichard Henderson             }
22887c4ee5bcSRichard Henderson             while (len) {
22897c4ee5bcSRichard Henderson                 int bytes_to_copy = (len > remaining) ? remaining : len;
22907c4ee5bcSRichard Henderson 
22917c4ee5bcSRichard Henderson                 memcpy_fromfs(scratch + (p - top), tmp, bytes_to_copy);
22927c4ee5bcSRichard Henderson 
22937c4ee5bcSRichard Henderson                 tmp += bytes_to_copy;
22947c4ee5bcSRichard Henderson                 remaining -= bytes_to_copy;
22957c4ee5bcSRichard Henderson                 p += bytes_to_copy;
22967c4ee5bcSRichard Henderson                 len -= bytes_to_copy;
22977c4ee5bcSRichard Henderson 
22987c4ee5bcSRichard Henderson                 if (remaining == 0) {
22997c4ee5bcSRichard Henderson                     memcpy_to_target(top, scratch, p - top);
23007c4ee5bcSRichard Henderson                     top = p;
23017c4ee5bcSRichard Henderson                     remaining = TARGET_PAGE_SIZE;
23027c4ee5bcSRichard Henderson                 }
23037c4ee5bcSRichard Henderson             }
23047c4ee5bcSRichard Henderson         }
23057c4ee5bcSRichard Henderson         if (p != top) {
23067c4ee5bcSRichard Henderson             memcpy_to_target(top, scratch, p - top);
23077c4ee5bcSRichard Henderson         }
23087c4ee5bcSRichard Henderson     }
230959baae9aSStefan Brüns 
231031e31b8aSbellard     return p;
231131e31b8aSbellard }
231231e31b8aSbellard 
231359baae9aSStefan Brüns /* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of
231459baae9aSStefan Brüns  * argument/environment space. Newer kernels (>2.6.33) allow more,
231559baae9aSStefan Brüns  * dependent on stack size, but guarantee at least 32 pages for
231659baae9aSStefan Brüns  * backwards compatibility.
231759baae9aSStefan Brüns  */
231859baae9aSStefan Brüns #define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE)
231959baae9aSStefan Brüns 
232059baae9aSStefan Brüns static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
232131e31b8aSbellard                                  struct image_info *info)
232231e31b8aSbellard {
232359baae9aSStefan Brüns     abi_ulong size, error, guard;
2324872f3d04SRichard Henderson     int prot;
232531e31b8aSbellard 
2326703e0e89SRichard Henderson     size = guest_stack_size;
232759baae9aSStefan Brüns     if (size < STACK_LOWER_LIMIT) {
232859baae9aSStefan Brüns         size = STACK_LOWER_LIMIT;
232960dcbcb5SRichard Henderson     }
2330f4388205SHelge Deller 
2331f4388205SHelge Deller     if (STACK_GROWS_DOWN) {
233260dcbcb5SRichard Henderson         guard = TARGET_PAGE_SIZE;
23338e3b0cbbSMarc-André Lureau         if (guard < qemu_real_host_page_size()) {
23348e3b0cbbSMarc-André Lureau             guard = qemu_real_host_page_size();
233560dcbcb5SRichard Henderson         }
2336f4388205SHelge Deller     } else {
2337f4388205SHelge Deller         /* no guard page for hppa target where stack grows upwards. */
2338f4388205SHelge Deller         guard = 0;
2339f4388205SHelge Deller     }
234060dcbcb5SRichard Henderson 
2341872f3d04SRichard Henderson     prot = PROT_READ | PROT_WRITE;
2342872f3d04SRichard Henderson     if (info->exec_stack) {
2343872f3d04SRichard Henderson         prot |= PROT_EXEC;
2344872f3d04SRichard Henderson     }
2345872f3d04SRichard Henderson     error = target_mmap(0, size + guard, prot,
234660dcbcb5SRichard Henderson                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
234709bfb054Sbellard     if (error == -1) {
234860dcbcb5SRichard Henderson         perror("mmap stack");
234931e31b8aSbellard         exit(-1);
235031e31b8aSbellard     }
235131e31b8aSbellard 
235260dcbcb5SRichard Henderson     /* We reserve one extra page at the top of the stack as guard.  */
23537c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
235460dcbcb5SRichard Henderson         target_mprotect(error, guard, PROT_NONE);
235560dcbcb5SRichard Henderson         info->stack_limit = error + guard;
235659baae9aSStefan Brüns         return info->stack_limit + size - sizeof(void *);
23577c4ee5bcSRichard Henderson     } else {
23587c4ee5bcSRichard Henderson         info->stack_limit = error + size;
23597c4ee5bcSRichard Henderson         return error;
23607c4ee5bcSRichard Henderson     }
236131e31b8aSbellard }
236231e31b8aSbellard 
23632d385be6SRichard Henderson /**
23642d385be6SRichard Henderson  * zero_bss:
23652d385be6SRichard Henderson  *
23662d385be6SRichard Henderson  * Map and zero the bss.  We need to explicitly zero any fractional pages
23672d385be6SRichard Henderson  * after the data section (i.e. bss).  Return false on mapping failure.
23682d385be6SRichard Henderson  */
2369e6e66b03SRichard Henderson static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss,
2370e6e66b03SRichard Henderson                      int prot, Error **errp)
237131e31b8aSbellard {
23722d385be6SRichard Henderson     abi_ulong align_bss;
2373cf129f3aSRichard Henderson 
2374e6e66b03SRichard Henderson     /* We only expect writable bss; the code segment shouldn't need this. */
2375e6e66b03SRichard Henderson     if (!(prot & PROT_WRITE)) {
2376e6e66b03SRichard Henderson         error_setg(errp, "PT_LOAD with non-writable bss");
2377e6e66b03SRichard Henderson         return false;
2378e6e66b03SRichard Henderson     }
2379e6e66b03SRichard Henderson 
23802d385be6SRichard Henderson     align_bss = TARGET_PAGE_ALIGN(start_bss);
23812d385be6SRichard Henderson     end_bss = TARGET_PAGE_ALIGN(end_bss);
2382cf129f3aSRichard Henderson 
23832d385be6SRichard Henderson     if (start_bss < align_bss) {
23842d385be6SRichard Henderson         int flags = page_get_flags(start_bss);
2385cf129f3aSRichard Henderson 
238686b7c551SBALATON Zoltan         if (!(flags & PAGE_RWX)) {
2387e6e66b03SRichard Henderson             /*
2388e6e66b03SRichard Henderson              * The whole address space of the executable was reserved
2389e6e66b03SRichard Henderson              * at the start, therefore all pages will be VALID.
2390e6e66b03SRichard Henderson              * But assuming there are no PROT_NONE PT_LOAD segments,
2391e6e66b03SRichard Henderson              * a PROT_NONE page means no data all bss, and we can
2392e6e66b03SRichard Henderson              * simply extend the new anon mapping back to the start
2393e6e66b03SRichard Henderson              * of the page of bss.
2394e6e66b03SRichard Henderson              */
23952d385be6SRichard Henderson             align_bss -= TARGET_PAGE_SIZE;
23962d385be6SRichard Henderson         } else {
2397e6e66b03SRichard Henderson             /*
2398e6e66b03SRichard Henderson              * The start of the bss shares a page with something.
2399e6e66b03SRichard Henderson              * The only thing that we expect is the data section,
2400e6e66b03SRichard Henderson              * which would already be marked writable.
2401e6e66b03SRichard Henderson              * Overlapping the RX code segment seems malformed.
2402e6e66b03SRichard Henderson              */
2403e6e66b03SRichard Henderson             if (!(flags & PAGE_WRITE)) {
2404e6e66b03SRichard Henderson                 error_setg(errp, "PT_LOAD with bss overlapping "
2405e6e66b03SRichard Henderson                            "non-writable page");
2406e6e66b03SRichard Henderson                 return false;
2407e6e66b03SRichard Henderson             }
2408e6e66b03SRichard Henderson 
2409e6e66b03SRichard Henderson             /* The page is already mapped and writable. */
2410e6e66b03SRichard Henderson             memset(g2h_untagged(start_bss), 0, align_bss - start_bss);
241131e31b8aSbellard         }
2412f46e9a0bSTom Musta     }
2413cf129f3aSRichard Henderson 
2414e6e66b03SRichard Henderson     if (align_bss < end_bss &&
24152d385be6SRichard Henderson         target_mmap(align_bss, end_bss - align_bss, prot,
2416e6e66b03SRichard Henderson                     MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) {
2417e6e66b03SRichard Henderson         error_setg_errno(errp, errno, "Error mapping bss");
2418e6e66b03SRichard Henderson         return false;
2419e6e66b03SRichard Henderson     }
2420e6e66b03SRichard Henderson     return true;
2421853d6f7aSbellard }
2422853d6f7aSbellard 
2423d2796be6SMax Filippov #if defined(TARGET_ARM)
2424cf58affeSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2425cf58affeSChristophe Lyon {
2426cf58affeSChristophe Lyon     return exec->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC;
2427cf58affeSChristophe Lyon }
2428d2796be6SMax Filippov #elif defined(TARGET_XTENSA)
2429d2796be6SMax Filippov static int elf_is_fdpic(struct elfhdr *exec)
2430d2796be6SMax Filippov {
2431d2796be6SMax Filippov     return exec->e_ident[EI_OSABI] == ELFOSABI_XTENSA_FDPIC;
2432d2796be6SMax Filippov }
2433cf58affeSChristophe Lyon #else
2434a99856cdSChristophe Lyon /* Default implementation, always false.  */
2435a99856cdSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2436a99856cdSChristophe Lyon {
2437a99856cdSChristophe Lyon     return 0;
2438a99856cdSChristophe Lyon }
2439cf58affeSChristophe Lyon #endif
2440a99856cdSChristophe Lyon 
24411af02e83SMike Frysinger static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
24421af02e83SMike Frysinger {
24431af02e83SMike Frysinger     uint16_t n;
24441af02e83SMike Frysinger     struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
24451af02e83SMike Frysinger 
24461af02e83SMike Frysinger     /* elf32_fdpic_loadseg */
24471af02e83SMike Frysinger     n = info->nsegs;
24481af02e83SMike Frysinger     while (n--) {
24491af02e83SMike Frysinger         sp -= 12;
24501af02e83SMike Frysinger         put_user_u32(loadsegs[n].addr, sp+0);
24511af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_vaddr, sp+4);
24521af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_memsz, sp+8);
24531af02e83SMike Frysinger     }
24541af02e83SMike Frysinger 
24551af02e83SMike Frysinger     /* elf32_fdpic_loadmap */
24561af02e83SMike Frysinger     sp -= 4;
24571af02e83SMike Frysinger     put_user_u16(0, sp+0); /* version */
24581af02e83SMike Frysinger     put_user_u16(info->nsegs, sp+2); /* nsegs */
24591af02e83SMike Frysinger 
24601af02e83SMike Frysinger     info->personality = PER_LINUX_FDPIC;
24611af02e83SMike Frysinger     info->loadmap_addr = sp;
24621af02e83SMike Frysinger 
24631af02e83SMike Frysinger     return sp;
24641af02e83SMike Frysinger }
24651af02e83SMike Frysinger 
2466992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
246731e31b8aSbellard                                    struct elfhdr *exec,
24688e62a717SRichard Henderson                                    struct image_info *info,
2469c40f621aSRichard Henderson                                    struct image_info *interp_info,
2470c40f621aSRichard Henderson                                    struct image_info *vdso_info)
247131e31b8aSbellard {
2472992f48a0Sblueswir1     abi_ulong sp;
24737c4ee5bcSRichard Henderson     abi_ulong u_argc, u_argv, u_envp, u_auxv;
247453a5960aSpbrook     int size;
247514322badSLaurent ALFONSI     int i;
247614322badSLaurent ALFONSI     abi_ulong u_rand_bytes;
247714322badSLaurent ALFONSI     uint8_t k_rand_bytes[16];
2478fcdc0ab4SJiaxun Yang     abi_ulong u_platform, u_base_platform;
2479fcdc0ab4SJiaxun Yang     const char *k_platform, *k_base_platform;
2480863cf0b7Sj_mayer     const int n = sizeof(elf_addr_t);
248131e31b8aSbellard 
248253a5960aSpbrook     sp = p;
24831af02e83SMike Frysinger 
24841af02e83SMike Frysinger     /* Needs to be before we load the env/argc/... */
24851af02e83SMike Frysinger     if (elf_is_fdpic(exec)) {
24861af02e83SMike Frysinger         /* Need 4 byte alignment for these structs */
24871af02e83SMike Frysinger         sp &= ~3;
24881af02e83SMike Frysinger         sp = loader_build_fdpic_loadmap(info, sp);
24891af02e83SMike Frysinger         info->other_info = interp_info;
24901af02e83SMike Frysinger         if (interp_info) {
24911af02e83SMike Frysinger             interp_info->other_info = info;
24921af02e83SMike Frysinger             sp = loader_build_fdpic_loadmap(interp_info, sp);
24933cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = interp_info->loadmap_addr;
24943cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = interp_info->pt_dynamic_addr;
24953cb10cfaSChristophe Lyon         } else {
24963cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = 0;
24973cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = 0;
24981af02e83SMike Frysinger         }
24991af02e83SMike Frysinger     }
25001af02e83SMike Frysinger 
2501fcdc0ab4SJiaxun Yang     u_base_platform = 0;
2502fcdc0ab4SJiaxun Yang     k_base_platform = ELF_BASE_PLATFORM;
2503fcdc0ab4SJiaxun Yang     if (k_base_platform) {
2504fcdc0ab4SJiaxun Yang         size_t len = strlen(k_base_platform) + 1;
2505fcdc0ab4SJiaxun Yang         if (STACK_GROWS_DOWN) {
2506fcdc0ab4SJiaxun Yang             sp -= (len + n - 1) & ~(n - 1);
2507fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2508fcdc0ab4SJiaxun Yang             /* FIXME - check return value of memcpy_to_target() for failure */
2509fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2510fcdc0ab4SJiaxun Yang         } else {
2511fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2512fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2513fcdc0ab4SJiaxun Yang             sp += len + 1;
2514fcdc0ab4SJiaxun Yang         }
2515fcdc0ab4SJiaxun Yang     }
2516fcdc0ab4SJiaxun Yang 
251753a5960aSpbrook     u_platform = 0;
251815338fd7Sbellard     k_platform = ELF_PLATFORM;
251915338fd7Sbellard     if (k_platform) {
252015338fd7Sbellard         size_t len = strlen(k_platform) + 1;
25217c4ee5bcSRichard Henderson         if (STACK_GROWS_DOWN) {
252253a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
252353a5960aSpbrook             u_platform = sp;
2524579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
252553a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
25267c4ee5bcSRichard Henderson         } else {
25277c4ee5bcSRichard Henderson             memcpy_to_target(sp, k_platform, len);
25287c4ee5bcSRichard Henderson             u_platform = sp;
25297c4ee5bcSRichard Henderson             sp += len + 1;
25307c4ee5bcSRichard Henderson         }
25317c4ee5bcSRichard Henderson     }
25327c4ee5bcSRichard Henderson 
25337c4ee5bcSRichard Henderson     /* Provide 16 byte alignment for the PRNG, and basic alignment for
25347c4ee5bcSRichard Henderson      * the argv and envp pointers.
25357c4ee5bcSRichard Henderson      */
25367c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
25377c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_DOWN(sp, 16);
25387c4ee5bcSRichard Henderson     } else {
25397c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp, 16);
254015338fd7Sbellard     }
254114322badSLaurent ALFONSI 
254214322badSLaurent ALFONSI     /*
2543c6a2377fSRichard Henderson      * Generate 16 random bytes for userspace PRNG seeding.
254414322badSLaurent ALFONSI      */
2545c6a2377fSRichard Henderson     qemu_guest_getrandom_nofail(k_rand_bytes, sizeof(k_rand_bytes));
25467c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
254714322badSLaurent ALFONSI         sp -= 16;
254814322badSLaurent ALFONSI         u_rand_bytes = sp;
254914322badSLaurent ALFONSI         /* FIXME - check return value of memcpy_to_target() for failure */
255014322badSLaurent ALFONSI         memcpy_to_target(sp, k_rand_bytes, 16);
25517c4ee5bcSRichard Henderson     } else {
25527c4ee5bcSRichard Henderson         memcpy_to_target(sp, k_rand_bytes, 16);
25537c4ee5bcSRichard Henderson         u_rand_bytes = sp;
25547c4ee5bcSRichard Henderson         sp += 16;
25557c4ee5bcSRichard Henderson     }
255614322badSLaurent ALFONSI 
255753a5960aSpbrook     size = (DLINFO_ITEMS + 1) * 2;
2558c40f621aSRichard Henderson     if (k_base_platform) {
2559fcdc0ab4SJiaxun Yang         size += 2;
2560c40f621aSRichard Henderson     }
2561c40f621aSRichard Henderson     if (k_platform) {
256253a5960aSpbrook         size += 2;
2563c40f621aSRichard Henderson     }
2564c40f621aSRichard Henderson     if (vdso_info) {
2565c40f621aSRichard Henderson         size += 2;
2566c40f621aSRichard Henderson     }
2567f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
256853a5960aSpbrook     size += DLINFO_ARCH_ITEMS * 2;
2569f5155289Sbellard #endif
2570ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2571ad6919dcSPeter Maydell     size += 2;
2572ad6919dcSPeter Maydell #endif
2573f516511eSPeter Maydell     info->auxv_len = size * n;
2574f516511eSPeter Maydell 
257553a5960aSpbrook     size += envc + argc + 2;
2576b9329d4bSRichard Henderson     size += 1;  /* argc itself */
257753a5960aSpbrook     size *= n;
25787c4ee5bcSRichard Henderson 
25797c4ee5bcSRichard Henderson     /* Allocate space and finalize stack alignment for entry now.  */
25807c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
25817c4ee5bcSRichard Henderson         u_argc = QEMU_ALIGN_DOWN(sp - size, STACK_ALIGNMENT);
25827c4ee5bcSRichard Henderson         sp = u_argc;
25837c4ee5bcSRichard Henderson     } else {
25847c4ee5bcSRichard Henderson         u_argc = sp;
25857c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp + size, STACK_ALIGNMENT);
25867c4ee5bcSRichard Henderson     }
25877c4ee5bcSRichard Henderson 
25887c4ee5bcSRichard Henderson     u_argv = u_argc + n;
25897c4ee5bcSRichard Henderson     u_envp = u_argv + (argc + 1) * n;
25907c4ee5bcSRichard Henderson     u_auxv = u_envp + (envc + 1) * n;
25917c4ee5bcSRichard Henderson     info->saved_auxv = u_auxv;
259260f1c801SRichard Henderson     info->argc = argc;
259360f1c801SRichard Henderson     info->envc = envc;
259460f1c801SRichard Henderson     info->argv = u_argv;
259560f1c801SRichard Henderson     info->envp = u_envp;
2596f5155289Sbellard 
2597863cf0b7Sj_mayer     /* This is correct because Linux defines
2598863cf0b7Sj_mayer      * elf_addr_t as Elf32_Off / Elf64_Off
2599863cf0b7Sj_mayer      */
260053a5960aSpbrook #define NEW_AUX_ENT(id, val) do {               \
26017c4ee5bcSRichard Henderson         put_user_ual(id, u_auxv);  u_auxv += n; \
26027c4ee5bcSRichard Henderson         put_user_ual(val, u_auxv); u_auxv += n; \
260353a5960aSpbrook     } while(0)
26042f619698Sbellard 
260582991bedSPeter Maydell #ifdef ARCH_DLINFO
260682991bedSPeter Maydell     /*
260782991bedSPeter Maydell      * ARCH_DLINFO must come first so platform specific code can enforce
260882991bedSPeter Maydell      * special alignment requirements on the AUXV if necessary (eg. PPC).
260982991bedSPeter Maydell      */
261082991bedSPeter Maydell     ARCH_DLINFO;
261182991bedSPeter Maydell #endif
2612f516511eSPeter Maydell     /* There must be exactly DLINFO_ITEMS entries here, or the assert
2613f516511eSPeter Maydell      * on info->auxv_len will trigger.
2614f516511eSPeter Maydell      */
26158e62a717SRichard Henderson     NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
2616992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
2617992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
261833143c44SLaurent Vivier     NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
26198e62a717SRichard Henderson     NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
2620992f48a0Sblueswir1     NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
26218e62a717SRichard Henderson     NEW_AUX_ENT(AT_ENTRY, info->entry);
2622992f48a0Sblueswir1     NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
2623992f48a0Sblueswir1     NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
2624992f48a0Sblueswir1     NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
2625992f48a0Sblueswir1     NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
2626992f48a0Sblueswir1     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
2627a07c67dfSpbrook     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
262814322badSLaurent ALFONSI     NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
2629444cd5c3SMarco A L Barbosa     NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
2630e0d1673dSLirong Yuan     NEW_AUX_ENT(AT_EXECFN, info->file_string);
263114322badSLaurent ALFONSI 
2632ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2633ad6919dcSPeter Maydell     NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
2634ad6919dcSPeter Maydell #endif
2635ad6919dcSPeter Maydell 
2636fcdc0ab4SJiaxun Yang     if (u_base_platform) {
2637fcdc0ab4SJiaxun Yang         NEW_AUX_ENT(AT_BASE_PLATFORM, u_base_platform);
2638fcdc0ab4SJiaxun Yang     }
26397c4ee5bcSRichard Henderson     if (u_platform) {
264053a5960aSpbrook         NEW_AUX_ENT(AT_PLATFORM, u_platform);
26417c4ee5bcSRichard Henderson     }
2642c40f621aSRichard Henderson     if (vdso_info) {
2643c40f621aSRichard Henderson         NEW_AUX_ENT(AT_SYSINFO_EHDR, vdso_info->load_addr);
2644c40f621aSRichard Henderson     }
26457c4ee5bcSRichard Henderson     NEW_AUX_ENT (AT_NULL, 0);
2646f5155289Sbellard #undef NEW_AUX_ENT
2647f5155289Sbellard 
2648f516511eSPeter Maydell     /* Check that our initial calculation of the auxv length matches how much
2649f516511eSPeter Maydell      * we actually put into it.
2650f516511eSPeter Maydell      */
2651f516511eSPeter Maydell     assert(info->auxv_len == u_auxv - info->saved_auxv);
2652edf8e2afSMika Westerberg 
26537c4ee5bcSRichard Henderson     put_user_ual(argc, u_argc);
26547c4ee5bcSRichard Henderson 
26557c4ee5bcSRichard Henderson     p = info->arg_strings;
26567c4ee5bcSRichard Henderson     for (i = 0; i < argc; ++i) {
26577c4ee5bcSRichard Henderson         put_user_ual(p, u_argv);
26587c4ee5bcSRichard Henderson         u_argv += n;
26597c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
26607c4ee5bcSRichard Henderson     }
26617c4ee5bcSRichard Henderson     put_user_ual(0, u_argv);
26627c4ee5bcSRichard Henderson 
26637c4ee5bcSRichard Henderson     p = info->env_strings;
26647c4ee5bcSRichard Henderson     for (i = 0; i < envc; ++i) {
26657c4ee5bcSRichard Henderson         put_user_ual(p, u_envp);
26667c4ee5bcSRichard Henderson         u_envp += n;
26677c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
26687c4ee5bcSRichard Henderson     }
26697c4ee5bcSRichard Henderson     put_user_ual(0, u_envp);
26707c4ee5bcSRichard Henderson 
267131e31b8aSbellard     return sp;
267231e31b8aSbellard }
267331e31b8aSbellard 
2674f5ef0e51SRichard Henderson #if defined(HI_COMMPAGE)
2675eee816c0SRichard Henderson #define LO_COMMPAGE -1
2676f5ef0e51SRichard Henderson #elif defined(LO_COMMPAGE)
267766346fafSRichard Henderson #define HI_COMMPAGE 0
2678f5ef0e51SRichard Henderson #else
2679f5ef0e51SRichard Henderson #define HI_COMMPAGE 0
2680eee816c0SRichard Henderson #define LO_COMMPAGE -1
2681d461b73eSRichard Henderson #ifndef INIT_GUEST_COMMPAGE
2682ee947430SAlex Bennée #define init_guest_commpage() true
2683ee947430SAlex Bennée #endif
2684d461b73eSRichard Henderson #endif
2685ee947430SAlex Bennée 
268606f38c66SRichard Henderson /**
268706f38c66SRichard Henderson  * pgb_try_mmap:
268806f38c66SRichard Henderson  * @addr: host start address
268906f38c66SRichard Henderson  * @addr_last: host last address
269006f38c66SRichard Henderson  * @keep: do not unmap the probe region
269106f38c66SRichard Henderson  *
269206f38c66SRichard Henderson  * Return 1 if [@addr, @addr_last] is not mapped in the host,
269306f38c66SRichard Henderson  * return 0 if it is not available to map, and -1 on mmap error.
269406f38c66SRichard Henderson  * If @keep, the region is left mapped on success, otherwise unmapped.
269506f38c66SRichard Henderson  */
269606f38c66SRichard Henderson static int pgb_try_mmap(uintptr_t addr, uintptr_t addr_last, bool keep)
269706f38c66SRichard Henderson {
269806f38c66SRichard Henderson     size_t size = addr_last - addr + 1;
269906f38c66SRichard Henderson     void *p = mmap((void *)addr, size, PROT_NONE,
270006f38c66SRichard Henderson                    MAP_ANONYMOUS | MAP_PRIVATE |
270106f38c66SRichard Henderson                    MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
270206f38c66SRichard Henderson     int ret;
270306f38c66SRichard Henderson 
270406f38c66SRichard Henderson     if (p == MAP_FAILED) {
270506f38c66SRichard Henderson         return errno == EEXIST ? 0 : -1;
270606f38c66SRichard Henderson     }
270706f38c66SRichard Henderson     ret = p == (void *)addr;
270806f38c66SRichard Henderson     if (!keep || !ret) {
270906f38c66SRichard Henderson         munmap(p, size);
271006f38c66SRichard Henderson     }
271106f38c66SRichard Henderson     return ret;
271206f38c66SRichard Henderson }
271306f38c66SRichard Henderson 
271406f38c66SRichard Henderson /**
271506f38c66SRichard Henderson  * pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t size, uintptr_t brk)
271606f38c66SRichard Henderson  * @addr: host address
271706f38c66SRichard Henderson  * @addr_last: host last address
271806f38c66SRichard Henderson  * @brk: host brk
271906f38c66SRichard Henderson  *
272006f38c66SRichard Henderson  * Like pgb_try_mmap, but additionally reserve some memory following brk.
272106f38c66SRichard Henderson  */
272206f38c66SRichard Henderson static int pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t addr_last,
272306f38c66SRichard Henderson                                  uintptr_t brk, bool keep)
272406f38c66SRichard Henderson {
272506f38c66SRichard Henderson     uintptr_t brk_last = brk + 16 * MiB - 1;
272606f38c66SRichard Henderson 
272706f38c66SRichard Henderson     /* Do not map anything close to the host brk. */
272806f38c66SRichard Henderson     if (addr <= brk_last && brk <= addr_last) {
272906f38c66SRichard Henderson         return 0;
273006f38c66SRichard Henderson     }
273106f38c66SRichard Henderson     return pgb_try_mmap(addr, addr_last, keep);
273206f38c66SRichard Henderson }
273306f38c66SRichard Henderson 
273406f38c66SRichard Henderson /**
273506f38c66SRichard Henderson  * pgb_try_mmap_set:
273606f38c66SRichard Henderson  * @ga: set of guest addrs
273706f38c66SRichard Henderson  * @base: guest_base
273806f38c66SRichard Henderson  * @brk: host brk
273906f38c66SRichard Henderson  *
274006f38c66SRichard Henderson  * Return true if all @ga can be mapped by the host at @base.
274106f38c66SRichard Henderson  * On success, retain the mapping at index 0 for reserved_va.
274206f38c66SRichard Henderson  */
274306f38c66SRichard Henderson 
274406f38c66SRichard Henderson typedef struct PGBAddrs {
274506f38c66SRichard Henderson     uintptr_t bounds[3][2]; /* start/last pairs */
274606f38c66SRichard Henderson     int nbounds;
274706f38c66SRichard Henderson } PGBAddrs;
274806f38c66SRichard Henderson 
274906f38c66SRichard Henderson static bool pgb_try_mmap_set(const PGBAddrs *ga, uintptr_t base, uintptr_t brk)
275006f38c66SRichard Henderson {
275106f38c66SRichard Henderson     for (int i = ga->nbounds - 1; i >= 0; --i) {
275206f38c66SRichard Henderson         if (pgb_try_mmap_skip_brk(ga->bounds[i][0] + base,
275306f38c66SRichard Henderson                                   ga->bounds[i][1] + base,
275406f38c66SRichard Henderson                                   brk, i == 0 && reserved_va) <= 0) {
275506f38c66SRichard Henderson             return false;
275606f38c66SRichard Henderson         }
275706f38c66SRichard Henderson     }
275806f38c66SRichard Henderson     return true;
275906f38c66SRichard Henderson }
276006f38c66SRichard Henderson 
276106f38c66SRichard Henderson /**
276206f38c66SRichard Henderson  * pgb_addr_set:
276306f38c66SRichard Henderson  * @ga: output set of guest addrs
276406f38c66SRichard Henderson  * @guest_loaddr: guest image low address
276506f38c66SRichard Henderson  * @guest_loaddr: guest image high address
276606f38c66SRichard Henderson  * @identity: create for identity mapping
276706f38c66SRichard Henderson  *
276806f38c66SRichard Henderson  * Fill in @ga with the image, COMMPAGE and NULL page.
276906f38c66SRichard Henderson  */
277006f38c66SRichard Henderson static bool pgb_addr_set(PGBAddrs *ga, abi_ulong guest_loaddr,
277106f38c66SRichard Henderson                          abi_ulong guest_hiaddr, bool try_identity)
277206f38c66SRichard Henderson {
277306f38c66SRichard Henderson     int n;
277406f38c66SRichard Henderson 
277506f38c66SRichard Henderson     /*
277606f38c66SRichard Henderson      * With a low commpage, or a guest mapped very low,
277706f38c66SRichard Henderson      * we may not be able to use the identity map.
277806f38c66SRichard Henderson      */
277906f38c66SRichard Henderson     if (try_identity) {
278006f38c66SRichard Henderson         if (LO_COMMPAGE != -1 && LO_COMMPAGE < mmap_min_addr) {
278106f38c66SRichard Henderson             return false;
278206f38c66SRichard Henderson         }
278306f38c66SRichard Henderson         if (guest_loaddr != 0 && guest_loaddr < mmap_min_addr) {
278406f38c66SRichard Henderson             return false;
278506f38c66SRichard Henderson         }
278606f38c66SRichard Henderson     }
278706f38c66SRichard Henderson 
278806f38c66SRichard Henderson     memset(ga, 0, sizeof(*ga));
278906f38c66SRichard Henderson     n = 0;
279006f38c66SRichard Henderson 
279106f38c66SRichard Henderson     if (reserved_va) {
279206f38c66SRichard Henderson         ga->bounds[n][0] = try_identity ? mmap_min_addr : 0;
279306f38c66SRichard Henderson         ga->bounds[n][1] = reserved_va;
279406f38c66SRichard Henderson         n++;
279506f38c66SRichard Henderson         /* LO_COMMPAGE and NULL handled by reserving from 0. */
279606f38c66SRichard Henderson     } else {
279706f38c66SRichard Henderson         /* Add any LO_COMMPAGE or NULL page. */
279806f38c66SRichard Henderson         if (LO_COMMPAGE != -1) {
279906f38c66SRichard Henderson             ga->bounds[n][0] = 0;
280006f38c66SRichard Henderson             ga->bounds[n][1] = LO_COMMPAGE + TARGET_PAGE_SIZE - 1;
280106f38c66SRichard Henderson             n++;
280206f38c66SRichard Henderson         } else if (!try_identity) {
280306f38c66SRichard Henderson             ga->bounds[n][0] = 0;
280406f38c66SRichard Henderson             ga->bounds[n][1] = TARGET_PAGE_SIZE - 1;
280506f38c66SRichard Henderson             n++;
280606f38c66SRichard Henderson         }
280706f38c66SRichard Henderson 
280806f38c66SRichard Henderson         /* Add the guest image for ET_EXEC. */
280906f38c66SRichard Henderson         if (guest_loaddr) {
281006f38c66SRichard Henderson             ga->bounds[n][0] = guest_loaddr;
281106f38c66SRichard Henderson             ga->bounds[n][1] = guest_hiaddr;
281206f38c66SRichard Henderson             n++;
281306f38c66SRichard Henderson         }
281406f38c66SRichard Henderson     }
281506f38c66SRichard Henderson 
281606f38c66SRichard Henderson     /*
281706f38c66SRichard Henderson      * Temporarily disable
281806f38c66SRichard Henderson      *   "comparison is always false due to limited range of data type"
281906f38c66SRichard Henderson      * due to comparison between unsigned and (possible) 0.
282006f38c66SRichard Henderson      */
282106f38c66SRichard Henderson #pragma GCC diagnostic push
282206f38c66SRichard Henderson #pragma GCC diagnostic ignored "-Wtype-limits"
282306f38c66SRichard Henderson 
282406f38c66SRichard Henderson     /* Add any HI_COMMPAGE not covered by reserved_va. */
282506f38c66SRichard Henderson     if (reserved_va < HI_COMMPAGE) {
2826ae6bffe0SRichard Henderson         ga->bounds[n][0] = HI_COMMPAGE & qemu_real_host_page_mask();
282706f38c66SRichard Henderson         ga->bounds[n][1] = HI_COMMPAGE + TARGET_PAGE_SIZE - 1;
282806f38c66SRichard Henderson         n++;
282906f38c66SRichard Henderson     }
283006f38c66SRichard Henderson 
283106f38c66SRichard Henderson #pragma GCC diagnostic pop
283206f38c66SRichard Henderson 
283306f38c66SRichard Henderson     ga->nbounds = n;
283406f38c66SRichard Henderson     return true;
283506f38c66SRichard Henderson }
283606f38c66SRichard Henderson 
2837ee947430SAlex Bennée static void pgb_fail_in_use(const char *image_name)
2838ee947430SAlex Bennée {
2839ee947430SAlex Bennée     error_report("%s: requires virtual address space that is in use "
2840ee947430SAlex Bennée                  "(omit the -B option or choose a different value)",
2841ee947430SAlex Bennée                  image_name);
2842ee947430SAlex Bennée     exit(EXIT_FAILURE);
2843ee947430SAlex Bennée }
2844ee947430SAlex Bennée 
284506f38c66SRichard Henderson static void pgb_fixed(const char *image_name, uintptr_t guest_loaddr,
284606f38c66SRichard Henderson                       uintptr_t guest_hiaddr, uintptr_t align)
2847ee947430SAlex Bennée {
284806f38c66SRichard Henderson     PGBAddrs ga;
284906f38c66SRichard Henderson     uintptr_t brk = (uintptr_t)sbrk(0);
2850ee947430SAlex Bennée 
2851ee947430SAlex Bennée     if (!QEMU_IS_ALIGNED(guest_base, align)) {
28525ca870b9SRichard Henderson         fprintf(stderr, "Requested guest base %p does not satisfy "
285306f38c66SRichard Henderson                 "host minimum alignment (0x%" PRIxPTR ")\n",
28545ca870b9SRichard Henderson                 (void *)guest_base, align);
2855ee947430SAlex Bennée         exit(EXIT_FAILURE);
2856ee947430SAlex Bennée     }
2857ee947430SAlex Bennée 
285806f38c66SRichard Henderson     if (!pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, !guest_base)
285906f38c66SRichard Henderson         || !pgb_try_mmap_set(&ga, guest_base, brk)) {
2860ee947430SAlex Bennée         pgb_fail_in_use(image_name);
2861ee947430SAlex Bennée     }
2862ee947430SAlex Bennée }
2863ee947430SAlex Bennée 
2864ad592e37SAlex Bennée /**
2865dd558855SRichard Henderson  * pgb_find_fallback:
2866ad592e37SAlex Bennée  *
2867dd558855SRichard Henderson  * This is a fallback method for finding holes in the host address space
2868dd558855SRichard Henderson  * if we don't have the benefit of being able to access /proc/self/map.
2869dd558855SRichard Henderson  * It can potentially take a very long time as we can only dumbly iterate
2870dd558855SRichard Henderson  * up the host address space seeing if the allocation would work.
2871ad592e37SAlex Bennée  */
2872dd558855SRichard Henderson static uintptr_t pgb_find_fallback(const PGBAddrs *ga, uintptr_t align,
2873dd558855SRichard Henderson                                    uintptr_t brk)
2874ad592e37SAlex Bennée {
2875dd558855SRichard Henderson     /* TODO: come up with a better estimate of how much to skip. */
2876dd558855SRichard Henderson     uintptr_t skip = sizeof(uintptr_t) == 4 ? MiB : GiB;
2877ad592e37SAlex Bennée 
2878dd558855SRichard Henderson     for (uintptr_t base = skip; ; base += skip) {
2879dd558855SRichard Henderson         base = ROUND_UP(base, align);
2880dd558855SRichard Henderson         if (pgb_try_mmap_set(ga, base, brk)) {
2881dd558855SRichard Henderson             return base;
2882dd558855SRichard Henderson         }
2883dd558855SRichard Henderson         if (base >= -skip) {
2884dd558855SRichard Henderson             return -1;
2885dd558855SRichard Henderson         }
2886dd558855SRichard Henderson     }
2887dd558855SRichard Henderson }
2888dd558855SRichard Henderson 
2889dd558855SRichard Henderson static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base,
2890dd558855SRichard Henderson                                IntervalTreeRoot *root)
2891dd558855SRichard Henderson {
2892dd558855SRichard Henderson     for (int i = ga->nbounds - 1; i >= 0; --i) {
2893dd558855SRichard Henderson         uintptr_t s = base + ga->bounds[i][0];
2894dd558855SRichard Henderson         uintptr_t l = base + ga->bounds[i][1];
2895dd558855SRichard Henderson         IntervalTreeNode *n;
2896dd558855SRichard Henderson 
2897dd558855SRichard Henderson         if (l < s) {
2898dd558855SRichard Henderson             /* Wraparound. Skip to advance S to mmap_min_addr. */
2899dd558855SRichard Henderson             return mmap_min_addr - s;
2900dd558855SRichard Henderson         }
2901dd558855SRichard Henderson 
2902dd558855SRichard Henderson         n = interval_tree_iter_first(root, s, l);
2903dd558855SRichard Henderson         if (n != NULL) {
2904dd558855SRichard Henderson             /* Conflict.  Skip to advance S to LAST + 1. */
2905dd558855SRichard Henderson             return n->last - s + 1;
2906dd558855SRichard Henderson         }
2907dd558855SRichard Henderson     }
2908dd558855SRichard Henderson     return 0;  /* success */
2909dd558855SRichard Henderson }
2910dd558855SRichard Henderson 
2911dd558855SRichard Henderson static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root,
2912dd558855SRichard Henderson                                 uintptr_t align, uintptr_t brk)
2913dd558855SRichard Henderson {
2914dd558855SRichard Henderson     uintptr_t last = mmap_min_addr;
2915dd558855SRichard Henderson     uintptr_t base, skip;
2916ad592e37SAlex Bennée 
2917ad592e37SAlex Bennée     while (true) {
2918dd558855SRichard Henderson         base = ROUND_UP(last, align);
2919dd558855SRichard Henderson         if (base < last) {
2920ad592e37SAlex Bennée             return -1;
2921ad592e37SAlex Bennée         }
2922dd558855SRichard Henderson 
2923dd558855SRichard Henderson         skip = pgb_try_itree(ga, base, root);
2924dd558855SRichard Henderson         if (skip == 0) {
2925dd558855SRichard Henderson             break;
29262667e069SAlex Bennée         }
2927dd558855SRichard Henderson 
2928dd558855SRichard Henderson         last = base + skip;
2929dd558855SRichard Henderson         if (last < base) {
2930dd558855SRichard Henderson             return -1;
2931ad592e37SAlex Bennée         }
2932ad592e37SAlex Bennée     }
2933ad592e37SAlex Bennée 
2934dd558855SRichard Henderson     /*
2935dd558855SRichard Henderson      * We've chosen 'base' based on holes in the interval tree,
2936dd558855SRichard Henderson      * but we don't yet know if it is a valid host address.
2937dd558855SRichard Henderson      * Because it is the first matching hole, if the host addresses
2938dd558855SRichard Henderson      * are invalid we know there are no further matches.
2939dd558855SRichard Henderson      */
2940dd558855SRichard Henderson     return pgb_try_mmap_set(ga, base, brk) ? base : -1;
2941dd558855SRichard Henderson }
2942dd558855SRichard Henderson 
2943dd558855SRichard Henderson static void pgb_dynamic(const char *image_name, uintptr_t guest_loaddr,
2944dd558855SRichard Henderson                         uintptr_t guest_hiaddr, uintptr_t align)
2945ee947430SAlex Bennée {
2946dd558855SRichard Henderson     IntervalTreeRoot *root;
2947dd558855SRichard Henderson     uintptr_t brk, ret;
2948dd558855SRichard Henderson     PGBAddrs ga;
2949ee947430SAlex Bennée 
2950dd558855SRichard Henderson     /* Try the identity map first. */
2951dd558855SRichard Henderson     if (pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, true)) {
2952dd558855SRichard Henderson         brk = (uintptr_t)sbrk(0);
2953dd558855SRichard Henderson         if (pgb_try_mmap_set(&ga, 0, brk)) {
2954dd558855SRichard Henderson             guest_base = 0;
2955dd558855SRichard Henderson             return;
2956dd558855SRichard Henderson         }
2957dd558855SRichard Henderson     }
2958dd558855SRichard Henderson 
2959dd558855SRichard Henderson     /*
2960dd558855SRichard Henderson      * Rebuild the address set for non-identity map.
2961dd558855SRichard Henderson      * This differs in the mapping of the guest NULL page.
2962dd558855SRichard Henderson      */
2963dd558855SRichard Henderson     pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, false);
2964dd558855SRichard Henderson 
2965dd558855SRichard Henderson     root = read_self_maps();
2966ee947430SAlex Bennée 
2967ee947430SAlex Bennée     /* Read brk after we've read the maps, which will malloc. */
2968ee947430SAlex Bennée     brk = (uintptr_t)sbrk(0);
2969ee947430SAlex Bennée 
2970dd558855SRichard Henderson     if (!root) {
2971dd558855SRichard Henderson         ret = pgb_find_fallback(&ga, align, brk);
2972ee947430SAlex Bennée     } else {
2973ee947430SAlex Bennée         /*
2974dd558855SRichard Henderson          * Reserve the area close to the host brk.
2975dd558855SRichard Henderson          * This will be freed with the rest of the tree.
2976ee947430SAlex Bennée          */
2977dd558855SRichard Henderson         IntervalTreeNode *b = g_new0(IntervalTreeNode, 1);
2978dd558855SRichard Henderson         b->start = brk;
2979dd558855SRichard Henderson         b->last = brk + 16 * MiB - 1;
2980dd558855SRichard Henderson         interval_tree_insert(b, root);
2981dd558855SRichard Henderson 
2982dd558855SRichard Henderson         ret = pgb_find_itree(&ga, root, align, brk);
2983dd558855SRichard Henderson         free_self_maps(root);
2984ee947430SAlex Bennée     }
2985ee947430SAlex Bennée 
2986dd558855SRichard Henderson     if (ret == -1) {
2987dd558855SRichard Henderson         int w = TARGET_LONG_BITS / 4;
2988dd558855SRichard Henderson 
2989dd558855SRichard Henderson         error_report("%s: Unable to find a guest_base to satisfy all "
2990dd558855SRichard Henderson                      "guest address mapping requirements", image_name);
2991dd558855SRichard Henderson 
2992dd558855SRichard Henderson         for (int i = 0; i < ga.nbounds; ++i) {
2993dd558855SRichard Henderson             error_printf("  %0*" PRIx64 "-%0*" PRIx64 "\n",
2994dd558855SRichard Henderson                          w, (uint64_t)ga.bounds[i][0],
2995dd558855SRichard Henderson                          w, (uint64_t)ga.bounds[i][1]);
2996dd558855SRichard Henderson         }
2997ee947430SAlex Bennée         exit(EXIT_FAILURE);
2998ee947430SAlex Bennée     }
2999dd558855SRichard Henderson     guest_base = ret;
3000ee947430SAlex Bennée }
3001ee947430SAlex Bennée 
3002ee947430SAlex Bennée void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
3003ee947430SAlex Bennée                       abi_ulong guest_hiaddr)
3004dce10401SMeador Inge {
300530ab9ef2SRichard Henderson     /* In order to use host shmat, we must be able to honor SHMLBA.  */
3006ae6bffe0SRichard Henderson     uintptr_t align = MAX(SHMLBA, TARGET_PAGE_SIZE);
3007dce10401SMeador Inge 
30080c441aebSRichard Henderson     /* Sanity check the guest binary. */
30090c441aebSRichard Henderson     if (reserved_va) {
30100c441aebSRichard Henderson         if (guest_hiaddr > reserved_va) {
30110c441aebSRichard Henderson             error_report("%s: requires more than reserved virtual "
30120c441aebSRichard Henderson                          "address space (0x%" PRIx64 " > 0x%lx)",
30130c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr, reserved_va);
30140c441aebSRichard Henderson             exit(EXIT_FAILURE);
30150c441aebSRichard Henderson         }
30160c441aebSRichard Henderson     } else {
30170c441aebSRichard Henderson         if (guest_hiaddr != (uintptr_t)guest_hiaddr) {
30180c441aebSRichard Henderson             error_report("%s: requires more virtual address space "
30190c441aebSRichard Henderson                          "than the host can provide (0x%" PRIx64 ")",
30200c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr + 1);
30210c441aebSRichard Henderson             exit(EXIT_FAILURE);
30220c441aebSRichard Henderson         }
30230c441aebSRichard Henderson     }
30240c441aebSRichard Henderson 
3025ee947430SAlex Bennée     if (have_guest_base) {
302606f38c66SRichard Henderson         pgb_fixed(image_name, guest_loaddr, guest_hiaddr, align);
3027293f2060SLuke Shumaker     } else {
3028dd558855SRichard Henderson         pgb_dynamic(image_name, guest_loaddr, guest_hiaddr, align);
3029806d1021SMeador Inge     }
3030806d1021SMeador Inge 
3031ee947430SAlex Bennée     /* Reserve and initialize the commpage. */
3032ee947430SAlex Bennée     if (!init_guest_commpage()) {
303306f38c66SRichard Henderson         /* We have already probed for the commpage being free. */
303406f38c66SRichard Henderson         g_assert_not_reached();
3035dce10401SMeador Inge     }
3036dce10401SMeador Inge 
3037ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_base, align));
3038ee947430SAlex Bennée     qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space "
3039ee947430SAlex Bennée                   "@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
3040dce10401SMeador Inge }
3041dce10401SMeador Inge 
304283f990ebSRichard Henderson enum {
304383f990ebSRichard Henderson     /* The string "GNU\0" as a magic number. */
304483f990ebSRichard Henderson     GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
304583f990ebSRichard Henderson     NOTE_DATA_SZ = 1 * KiB,
304683f990ebSRichard Henderson     NOTE_NAME_SZ = 4,
304783f990ebSRichard Henderson     ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
304883f990ebSRichard Henderson };
304983f990ebSRichard Henderson 
305083f990ebSRichard Henderson /*
305183f990ebSRichard Henderson  * Process a single gnu_property entry.
305283f990ebSRichard Henderson  * Return false for error.
305383f990ebSRichard Henderson  */
305483f990ebSRichard Henderson static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
305583f990ebSRichard Henderson                                struct image_info *info, bool have_prev_type,
305683f990ebSRichard Henderson                                uint32_t *prev_type, Error **errp)
305783f990ebSRichard Henderson {
305883f990ebSRichard Henderson     uint32_t pr_type, pr_datasz, step;
305983f990ebSRichard Henderson 
306083f990ebSRichard Henderson     if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
306183f990ebSRichard Henderson         goto error_data;
306283f990ebSRichard Henderson     }
306383f990ebSRichard Henderson     datasz -= *off;
306483f990ebSRichard Henderson     data += *off / sizeof(uint32_t);
306583f990ebSRichard Henderson 
306683f990ebSRichard Henderson     if (datasz < 2 * sizeof(uint32_t)) {
306783f990ebSRichard Henderson         goto error_data;
306883f990ebSRichard Henderson     }
306983f990ebSRichard Henderson     pr_type = data[0];
307083f990ebSRichard Henderson     pr_datasz = data[1];
307183f990ebSRichard Henderson     data += 2;
307283f990ebSRichard Henderson     datasz -= 2 * sizeof(uint32_t);
307383f990ebSRichard Henderson     step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
307483f990ebSRichard Henderson     if (step > datasz) {
307583f990ebSRichard Henderson         goto error_data;
307683f990ebSRichard Henderson     }
307783f990ebSRichard Henderson 
307883f990ebSRichard Henderson     /* Properties are supposed to be unique and sorted on pr_type. */
307983f990ebSRichard Henderson     if (have_prev_type && pr_type <= *prev_type) {
308083f990ebSRichard Henderson         if (pr_type == *prev_type) {
308183f990ebSRichard Henderson             error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
308283f990ebSRichard Henderson         } else {
308383f990ebSRichard Henderson             error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
308483f990ebSRichard Henderson         }
308583f990ebSRichard Henderson         return false;
308683f990ebSRichard Henderson     }
308783f990ebSRichard Henderson     *prev_type = pr_type;
308883f990ebSRichard Henderson 
308983f990ebSRichard Henderson     if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
309083f990ebSRichard Henderson         return false;
309183f990ebSRichard Henderson     }
309283f990ebSRichard Henderson 
309383f990ebSRichard Henderson     *off += 2 * sizeof(uint32_t) + step;
309483f990ebSRichard Henderson     return true;
309583f990ebSRichard Henderson 
309683f990ebSRichard Henderson  error_data:
309783f990ebSRichard Henderson     error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
309883f990ebSRichard Henderson     return false;
309983f990ebSRichard Henderson }
310083f990ebSRichard Henderson 
310183f990ebSRichard Henderson /* Process NT_GNU_PROPERTY_TYPE_0. */
31023bd02386SRichard Henderson static bool parse_elf_properties(const ImageSource *src,
310383f990ebSRichard Henderson                                  struct image_info *info,
310483f990ebSRichard Henderson                                  const struct elf_phdr *phdr,
310583f990ebSRichard Henderson                                  Error **errp)
310683f990ebSRichard Henderson {
310783f990ebSRichard Henderson     union {
310883f990ebSRichard Henderson         struct elf_note nhdr;
310983f990ebSRichard Henderson         uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
311083f990ebSRichard Henderson     } note;
311183f990ebSRichard Henderson 
311283f990ebSRichard Henderson     int n, off, datasz;
311383f990ebSRichard Henderson     bool have_prev_type;
311483f990ebSRichard Henderson     uint32_t prev_type;
311583f990ebSRichard Henderson 
311683f990ebSRichard Henderson     /* Unless the arch requires properties, ignore them. */
311783f990ebSRichard Henderson     if (!ARCH_USE_GNU_PROPERTY) {
311883f990ebSRichard Henderson         return true;
311983f990ebSRichard Henderson     }
312083f990ebSRichard Henderson 
312183f990ebSRichard Henderson     /* If the properties are crazy large, that's too bad. */
312283f990ebSRichard Henderson     n = phdr->p_filesz;
312383f990ebSRichard Henderson     if (n > sizeof(note)) {
312483f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too large");
312583f990ebSRichard Henderson         return false;
312683f990ebSRichard Henderson     }
312783f990ebSRichard Henderson     if (n < sizeof(note.nhdr)) {
312883f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too small");
312983f990ebSRichard Henderson         return false;
313083f990ebSRichard Henderson     }
313183f990ebSRichard Henderson 
31323bd02386SRichard Henderson     if (!imgsrc_read(&note, phdr->p_offset, n, src, errp)) {
313383f990ebSRichard Henderson         return false;
313483f990ebSRichard Henderson     }
313583f990ebSRichard Henderson 
313683f990ebSRichard Henderson     /*
313783f990ebSRichard Henderson      * The contents of a valid PT_GNU_PROPERTY is a sequence
313883f990ebSRichard Henderson      * of uint32_t -- swap them all now.
313983f990ebSRichard Henderson      */
314083f990ebSRichard Henderson #ifdef BSWAP_NEEDED
314183f990ebSRichard Henderson     for (int i = 0; i < n / 4; i++) {
314283f990ebSRichard Henderson         bswap32s(note.data + i);
314383f990ebSRichard Henderson     }
314483f990ebSRichard Henderson #endif
314583f990ebSRichard Henderson 
314683f990ebSRichard Henderson     /*
314783f990ebSRichard Henderson      * Note that nhdr is 3 words, and that the "name" described by namesz
314883f990ebSRichard Henderson      * immediately follows nhdr and is thus at the 4th word.  Further, all
314983f990ebSRichard Henderson      * of the inputs to the kernel's round_up are multiples of 4.
315083f990ebSRichard Henderson      */
315183f990ebSRichard Henderson     if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
315283f990ebSRichard Henderson         note.nhdr.n_namesz != NOTE_NAME_SZ ||
315383f990ebSRichard Henderson         note.data[3] != GNU0_MAGIC) {
315483f990ebSRichard Henderson         error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
315583f990ebSRichard Henderson         return false;
315683f990ebSRichard Henderson     }
315783f990ebSRichard Henderson     off = sizeof(note.nhdr) + NOTE_NAME_SZ;
315883f990ebSRichard Henderson 
315983f990ebSRichard Henderson     datasz = note.nhdr.n_descsz + off;
316083f990ebSRichard Henderson     if (datasz > n) {
316183f990ebSRichard Henderson         error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
316283f990ebSRichard Henderson         return false;
316383f990ebSRichard Henderson     }
316483f990ebSRichard Henderson 
316583f990ebSRichard Henderson     have_prev_type = false;
316683f990ebSRichard Henderson     prev_type = 0;
316783f990ebSRichard Henderson     while (1) {
316883f990ebSRichard Henderson         if (off == datasz) {
316983f990ebSRichard Henderson             return true;  /* end, exit ok */
317083f990ebSRichard Henderson         }
317183f990ebSRichard Henderson         if (!parse_elf_property(note.data, &off, datasz, info,
317283f990ebSRichard Henderson                                 have_prev_type, &prev_type, errp)) {
317383f990ebSRichard Henderson             return false;
317483f990ebSRichard Henderson         }
317583f990ebSRichard Henderson         have_prev_type = true;
317683f990ebSRichard Henderson     }
317783f990ebSRichard Henderson }
317883f990ebSRichard Henderson 
31793bd02386SRichard Henderson /**
31803bd02386SRichard Henderson  * load_elf_image: Load an ELF image into the address space.
31813bd02386SRichard Henderson  * @image_name: the filename of the image, to use in error messages.
31823bd02386SRichard Henderson  * @src: the ImageSource from which to read.
31833bd02386SRichard Henderson  * @info: info collected from the loaded image.
31843bd02386SRichard Henderson  * @ehdr: the ELF header, not yet bswapped.
31853bd02386SRichard Henderson  * @pinterp_name: record any PT_INTERP string found.
31863bd02386SRichard Henderson  *
31873bd02386SRichard Henderson  * On return: @info values will be filled in, as necessary or available.
31883bd02386SRichard Henderson  */
318931e31b8aSbellard 
31903bd02386SRichard Henderson static void load_elf_image(const char *image_name, const ImageSource *src,
319140d487eeSRichard Henderson                            struct image_info *info, struct elfhdr *ehdr,
31923bd02386SRichard Henderson                            char **pinterp_name)
319331e31b8aSbellard {
31943bd02386SRichard Henderson     g_autofree struct elf_phdr *phdr = NULL;
31958e62a717SRichard Henderson     abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
31963bd02386SRichard Henderson     int i, prot_exec;
3197c7f17e7bSRichard Henderson     Error *err = NULL;
319831e31b8aSbellard 
31993bd02386SRichard Henderson     /*
32003bd02386SRichard Henderson      * First of all, some simple consistency checks.
32013bd02386SRichard Henderson      * Note that we rely on the bswapped ehdr staying in bprm_buf,
32023bd02386SRichard Henderson      * for later use by load_elf_binary and create_elf_tables.
32033bd02386SRichard Henderson      */
32043bd02386SRichard Henderson     if (!imgsrc_read(ehdr, 0, sizeof(*ehdr), src, &err)) {
32053bd02386SRichard Henderson         goto exit_errmsg;
32063bd02386SRichard Henderson     }
32078e62a717SRichard Henderson     if (!elf_check_ident(ehdr)) {
3208c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
32098e62a717SRichard Henderson         goto exit_errmsg;
32108e62a717SRichard Henderson     }
32118e62a717SRichard Henderson     bswap_ehdr(ehdr);
32128e62a717SRichard Henderson     if (!elf_check_ehdr(ehdr)) {
3213c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
32148e62a717SRichard Henderson         goto exit_errmsg;
321531e31b8aSbellard     }
321631e31b8aSbellard 
32173bd02386SRichard Henderson     phdr = imgsrc_read_alloc(ehdr->e_phoff,
32183bd02386SRichard Henderson                              ehdr->e_phnum * sizeof(struct elf_phdr),
32193bd02386SRichard Henderson                              src, &err);
32203bd02386SRichard Henderson     if (phdr == NULL) {
32213bd02386SRichard Henderson         goto exit_errmsg;
322231e31b8aSbellard     }
32238e62a717SRichard Henderson     bswap_phdr(phdr, ehdr->e_phnum);
322409bfb054Sbellard 
32251af02e83SMike Frysinger     info->nsegs = 0;
32261af02e83SMike Frysinger     info->pt_dynamic_addr = 0;
32271af02e83SMike Frysinger 
322898c1076cSAlex Bennée     mmap_lock();
322998c1076cSAlex Bennée 
32308a1a5274SRichard Henderson     /*
32318a1a5274SRichard Henderson      * Find the maximum size of the image and allocate an appropriate
32328a1a5274SRichard Henderson      * amount of memory to handle that.  Locate the interpreter, if any.
32338a1a5274SRichard Henderson      */
3234682674b8SRichard Henderson     loaddr = -1, hiaddr = 0;
323533143c44SLaurent Vivier     info->alignment = 0;
3236872f3d04SRichard Henderson     info->exec_stack = EXSTACK_DEFAULT;
32378e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; ++i) {
32384d9d535aSRichard Henderson         struct elf_phdr *eppnt = phdr + i;
32394d9d535aSRichard Henderson         if (eppnt->p_type == PT_LOAD) {
324082d70a84SRichard Henderson             abi_ulong a = eppnt->p_vaddr & TARGET_PAGE_MASK;
3241682674b8SRichard Henderson             if (a < loaddr) {
3242682674b8SRichard Henderson                 loaddr = a;
3243682674b8SRichard Henderson             }
3244a3a67f54SRichard Henderson             a = eppnt->p_vaddr + eppnt->p_memsz - 1;
3245682674b8SRichard Henderson             if (a > hiaddr) {
3246682674b8SRichard Henderson                 hiaddr = a;
3247682674b8SRichard Henderson             }
32481af02e83SMike Frysinger             ++info->nsegs;
32494d9d535aSRichard Henderson             info->alignment |= eppnt->p_align;
32508a1a5274SRichard Henderson         } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
32518a1a5274SRichard Henderson             g_autofree char *interp_name = NULL;
32528a1a5274SRichard Henderson 
32538a1a5274SRichard Henderson             if (*pinterp_name) {
3254c7f17e7bSRichard Henderson                 error_setg(&err, "Multiple PT_INTERP entries");
32558a1a5274SRichard Henderson                 goto exit_errmsg;
32568a1a5274SRichard Henderson             }
3257c7f17e7bSRichard Henderson 
32583bd02386SRichard Henderson             interp_name = imgsrc_read_alloc(eppnt->p_offset, eppnt->p_filesz,
32593bd02386SRichard Henderson                                             src, &err);
32603bd02386SRichard Henderson             if (interp_name == NULL) {
32613bd02386SRichard Henderson                 goto exit_errmsg;
32628a1a5274SRichard Henderson             }
32638a1a5274SRichard Henderson             if (interp_name[eppnt->p_filesz - 1] != 0) {
3264c7f17e7bSRichard Henderson                 error_setg(&err, "Invalid PT_INTERP entry");
32658a1a5274SRichard Henderson                 goto exit_errmsg;
32668a1a5274SRichard Henderson             }
32678a1a5274SRichard Henderson             *pinterp_name = g_steal_pointer(&interp_name);
326883f990ebSRichard Henderson         } else if (eppnt->p_type == PT_GNU_PROPERTY) {
32693bd02386SRichard Henderson             if (!parse_elf_properties(src, info, eppnt, &err)) {
327083f990ebSRichard Henderson                 goto exit_errmsg;
327183f990ebSRichard Henderson             }
3272872f3d04SRichard Henderson         } else if (eppnt->p_type == PT_GNU_STACK) {
3273872f3d04SRichard Henderson             info->exec_stack = eppnt->p_flags & PF_X;
3274682674b8SRichard Henderson         }
3275682674b8SRichard Henderson     }
3276682674b8SRichard Henderson 
32771ea06dedSRichard Henderson     load_addr = loaddr;
32781ea06dedSRichard Henderson 
32796fd59449SRichard Henderson     if (pinterp_name != NULL) {
32806fd59449SRichard Henderson         if (ehdr->e_type == ET_EXEC) {
32816fd59449SRichard Henderson             /*
32826fd59449SRichard Henderson              * Make sure that the low address does not conflict with
32836fd59449SRichard Henderson              * MMAP_MIN_ADDR or the QEMU application itself.
32846fd59449SRichard Henderson              */
32856fd59449SRichard Henderson             probe_guest_base(image_name, loaddr, hiaddr);
3286ee947430SAlex Bennée         } else {
32871ea06dedSRichard Henderson             abi_ulong align;
32881ea06dedSRichard Henderson 
3289ee947430SAlex Bennée             /*
3290ee947430SAlex Bennée              * The binary is dynamic, but we still need to
3291ee947430SAlex Bennée              * select guest_base.  In this case we pass a size.
3292ee947430SAlex Bennée              */
3293ee947430SAlex Bennée             probe_guest_base(image_name, 0, hiaddr - loaddr);
32941ea06dedSRichard Henderson 
32951ea06dedSRichard Henderson             /*
32961ea06dedSRichard Henderson              * Avoid collision with the loader by providing a different
32971ea06dedSRichard Henderson              * default load address.
32981ea06dedSRichard Henderson              */
32991ea06dedSRichard Henderson             load_addr += elf_et_dyn_base;
33001ea06dedSRichard Henderson 
33011ea06dedSRichard Henderson             /*
33021ea06dedSRichard Henderson              * TODO: Better support for mmap alignment is desirable.
33031ea06dedSRichard Henderson              * Since we do not have complete control over the guest
33041ea06dedSRichard Henderson              * address space, we prefer the kernel to choose some address
33051ea06dedSRichard Henderson              * rather than force the use of LOAD_ADDR via MAP_FIXED.
33061ea06dedSRichard Henderson              * But without MAP_FIXED we cannot guarantee alignment,
33071ea06dedSRichard Henderson              * only suggest it.
33081ea06dedSRichard Henderson              */
33091ea06dedSRichard Henderson             align = pow2ceil(info->alignment);
33101ea06dedSRichard Henderson             if (align) {
33111ea06dedSRichard Henderson                 load_addr &= -align;
33121ea06dedSRichard Henderson             }
33136fd59449SRichard Henderson         }
33146fd59449SRichard Henderson     }
33156fd59449SRichard Henderson 
33166fd59449SRichard Henderson     /*
33176fd59449SRichard Henderson      * Reserve address space for all of this.
33186fd59449SRichard Henderson      *
3319ad25051bSRichard Henderson      * In the case of ET_EXEC, we supply MAP_FIXED_NOREPLACE so that we get
3320ad25051bSRichard Henderson      * exactly the address range that is required.  Without reserved_va,
3321ad25051bSRichard Henderson      * the guest address space is not isolated.  We have attempted to avoid
3322ad25051bSRichard Henderson      * conflict with the host program itself via probe_guest_base, but using
3323ad25051bSRichard Henderson      * MAP_FIXED_NOREPLACE instead of MAP_FIXED provides an extra check.
33246fd59449SRichard Henderson      *
33256fd59449SRichard Henderson      * Otherwise this is ET_DYN, and we are searching for a location
33266fd59449SRichard Henderson      * that can hold the memory space required.  If the image is
33271ea06dedSRichard Henderson      * pre-linked, LOAD_ADDR will be non-zero, and the kernel should
33286fd59449SRichard Henderson      * honor that address if it happens to be free.
33296fd59449SRichard Henderson      *
33306fd59449SRichard Henderson      * In both cases, we will overwrite pages in this range with mappings
33316fd59449SRichard Henderson      * from the executable.
33326fd59449SRichard Henderson      */
33331ea06dedSRichard Henderson     load_addr = target_mmap(load_addr, (size_t)hiaddr - loaddr + 1, PROT_NONE,
33346fd59449SRichard Henderson                             MAP_PRIVATE | MAP_ANON | MAP_NORESERVE |
3335ad25051bSRichard Henderson                             (ehdr->e_type == ET_EXEC ? MAP_FIXED_NOREPLACE : 0),
333609bfb054Sbellard                             -1, 0);
3337682674b8SRichard Henderson     if (load_addr == -1) {
3338c7f17e7bSRichard Henderson         goto exit_mmap;
333909bfb054Sbellard     }
3340682674b8SRichard Henderson     load_bias = load_addr - loaddr;
334109bfb054Sbellard 
3342a99856cdSChristophe Lyon     if (elf_is_fdpic(ehdr)) {
33431af02e83SMike Frysinger         struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
33447267c094SAnthony Liguori             g_malloc(sizeof(*loadsegs) * info->nsegs);
33451af02e83SMike Frysinger 
33461af02e83SMike Frysinger         for (i = 0; i < ehdr->e_phnum; ++i) {
33471af02e83SMike Frysinger             switch (phdr[i].p_type) {
33481af02e83SMike Frysinger             case PT_DYNAMIC:
33491af02e83SMike Frysinger                 info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
33501af02e83SMike Frysinger                 break;
33511af02e83SMike Frysinger             case PT_LOAD:
33521af02e83SMike Frysinger                 loadsegs->addr = phdr[i].p_vaddr + load_bias;
33531af02e83SMike Frysinger                 loadsegs->p_vaddr = phdr[i].p_vaddr;
33541af02e83SMike Frysinger                 loadsegs->p_memsz = phdr[i].p_memsz;
33551af02e83SMike Frysinger                 ++loadsegs;
33561af02e83SMike Frysinger                 break;
33571af02e83SMike Frysinger             }
33581af02e83SMike Frysinger         }
33591af02e83SMike Frysinger     }
33601af02e83SMike Frysinger 
33618e62a717SRichard Henderson     info->load_bias = load_bias;
3362dc12567aSJosh Kunz     info->code_offset = load_bias;
3363dc12567aSJosh Kunz     info->data_offset = load_bias;
33648e62a717SRichard Henderson     info->load_addr = load_addr;
33658e62a717SRichard Henderson     info->entry = ehdr->e_entry + load_bias;
33668e62a717SRichard Henderson     info->start_code = -1;
33678e62a717SRichard Henderson     info->end_code = 0;
33688e62a717SRichard Henderson     info->start_data = -1;
33698e62a717SRichard Henderson     info->end_data = 0;
33701f356e8cSHelge Deller     /* Usual start for brk is after all sections of the main executable. */
3371aec338d6SRichard Henderson     info->brk = TARGET_PAGE_ALIGN(hiaddr + load_bias);
3372d8fd2954SPaul Brook     info->elf_flags = ehdr->e_flags;
33738e62a717SRichard Henderson 
3374e8384b37SRichard Henderson     prot_exec = PROT_EXEC;
3375e8384b37SRichard Henderson #ifdef TARGET_AARCH64
3376e8384b37SRichard Henderson     /*
3377e8384b37SRichard Henderson      * If the BTI feature is present, this indicates that the executable
3378e8384b37SRichard Henderson      * pages of the startup binary should be mapped with PROT_BTI, so that
3379e8384b37SRichard Henderson      * branch targets are enforced.
3380e8384b37SRichard Henderson      *
3381e8384b37SRichard Henderson      * The startup binary is either the interpreter or the static executable.
3382e8384b37SRichard Henderson      * The interpreter is responsible for all pages of a dynamic executable.
3383e8384b37SRichard Henderson      *
3384e8384b37SRichard Henderson      * Elf notes are backward compatible to older cpus.
3385e8384b37SRichard Henderson      * Do not enable BTI unless it is supported.
3386e8384b37SRichard Henderson      */
3387e8384b37SRichard Henderson     if ((info->note_flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
3388e8384b37SRichard Henderson         && (pinterp_name == NULL || *pinterp_name == 0)
3389e8384b37SRichard Henderson         && cpu_isar_feature(aa64_bti, ARM_CPU(thread_cpu))) {
3390e8384b37SRichard Henderson         prot_exec |= TARGET_PROT_BTI;
3391e8384b37SRichard Henderson     }
3392e8384b37SRichard Henderson #endif
3393e8384b37SRichard Henderson 
33948e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; i++) {
33958e62a717SRichard Henderson         struct elf_phdr *eppnt = phdr + i;
339631e31b8aSbellard         if (eppnt->p_type == PT_LOAD) {
33975f4e5b34SRichard Henderson             abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
339831e31b8aSbellard             int elf_prot = 0;
339931e31b8aSbellard 
3400e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_R) {
3401e5eaf570SRichard Henderson                 elf_prot |= PROT_READ;
3402e5eaf570SRichard Henderson             }
3403e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_W) {
3404e5eaf570SRichard Henderson                 elf_prot |= PROT_WRITE;
3405e5eaf570SRichard Henderson             }
3406e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_X) {
3407e8384b37SRichard Henderson                 elf_prot |= prot_exec;
3408e5eaf570SRichard Henderson             }
340931e31b8aSbellard 
3410682674b8SRichard Henderson             vaddr = load_bias + eppnt->p_vaddr;
3411e3d97d5cSRichard Henderson             vaddr_po = vaddr & ~TARGET_PAGE_MASK;
3412e3d97d5cSRichard Henderson             vaddr_ps = vaddr & TARGET_PAGE_MASK;
341322d113b5SGiuseppe Musacchio 
341422d113b5SGiuseppe Musacchio             vaddr_ef = vaddr + eppnt->p_filesz;
341522d113b5SGiuseppe Musacchio             vaddr_em = vaddr + eppnt->p_memsz;
3416682674b8SRichard Henderson 
3417d87146bcSGiuseppe Musacchio             /*
341822d113b5SGiuseppe Musacchio              * Some segments may be completely empty, with a non-zero p_memsz
341922d113b5SGiuseppe Musacchio              * but no backing file segment.
3420d87146bcSGiuseppe Musacchio              */
3421d87146bcSGiuseppe Musacchio             if (eppnt->p_filesz != 0) {
34223bd02386SRichard Henderson                 error = imgsrc_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
34235f4e5b34SRichard Henderson                                     elf_prot, MAP_PRIVATE | MAP_FIXED,
34243bd02386SRichard Henderson                                     src, eppnt->p_offset - vaddr_po);
3425e89f07d3Spbrook                 if (error == -1) {
3426c7f17e7bSRichard Henderson                     goto exit_mmap;
342731e31b8aSbellard                 }
34285f4e5b34SRichard Henderson             }
342931e31b8aSbellard 
34305f4e5b34SRichard Henderson             /* If the load segment requests extra zeros (e.g. bss), map it. */
34315f4e5b34SRichard Henderson             if (vaddr_ef < vaddr_em &&
3432e6e66b03SRichard Henderson                 !zero_bss(vaddr_ef, vaddr_em, elf_prot, &err)) {
3433e6e66b03SRichard Henderson                 goto exit_errmsg;
3434682674b8SRichard Henderson             }
34358e62a717SRichard Henderson 
34368e62a717SRichard Henderson             /* Find the full program boundaries.  */
34378e62a717SRichard Henderson             if (elf_prot & PROT_EXEC) {
34388e62a717SRichard Henderson                 if (vaddr < info->start_code) {
34398e62a717SRichard Henderson                     info->start_code = vaddr;
3440cf129f3aSRichard Henderson                 }
34418e62a717SRichard Henderson                 if (vaddr_ef > info->end_code) {
34428e62a717SRichard Henderson                     info->end_code = vaddr_ef;
34438e62a717SRichard Henderson                 }
34448e62a717SRichard Henderson             }
34458e62a717SRichard Henderson             if (elf_prot & PROT_WRITE) {
34468e62a717SRichard Henderson                 if (vaddr < info->start_data) {
34478e62a717SRichard Henderson                     info->start_data = vaddr;
34488e62a717SRichard Henderson                 }
34498e62a717SRichard Henderson                 if (vaddr_ef > info->end_data) {
34508e62a717SRichard Henderson                     info->end_data = vaddr_ef;
34518e62a717SRichard Henderson                 }
34528a045188STimothy E Baldwin             }
34535dd0db52SStefan Markovic #ifdef TARGET_MIPS
34545dd0db52SStefan Markovic         } else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
34555dd0db52SStefan Markovic             Mips_elf_abiflags_v0 abiflags;
34563bd02386SRichard Henderson 
34573bd02386SRichard Henderson             if (!imgsrc_read(&abiflags, eppnt->p_offset, sizeof(abiflags),
34583bd02386SRichard Henderson                              src, &err)) {
34595dd0db52SStefan Markovic                 goto exit_errmsg;
34605dd0db52SStefan Markovic             }
34615dd0db52SStefan Markovic             bswap_mips_abiflags(&abiflags);
3462c94cb6c9SStefan Markovic             info->fp_abi = abiflags.fp_abi;
34635dd0db52SStefan Markovic #endif
34648e62a717SRichard Henderson         }
34658e62a717SRichard Henderson     }
34668e62a717SRichard Henderson 
34678e62a717SRichard Henderson     if (info->end_data == 0) {
34688e62a717SRichard Henderson         info->start_data = info->end_code;
34698e62a717SRichard Henderson         info->end_data = info->end_code;
347031e31b8aSbellard     }
347131e31b8aSbellard 
3472682674b8SRichard Henderson     if (qemu_log_enabled()) {
347386cf82dcSRichard Henderson         load_symbols(ehdr, src, load_bias);
3474682674b8SRichard Henderson     }
347531e31b8aSbellard 
34763bd02386SRichard Henderson     debuginfo_report_elf(image_name, src->fd, load_bias);
34777c10cb38SIlya Leoshkevich 
347898c1076cSAlex Bennée     mmap_unlock();
347998c1076cSAlex Bennée 
34803bd02386SRichard Henderson     close(src->fd);
34818e62a717SRichard Henderson     return;
348231e31b8aSbellard 
3483c7f17e7bSRichard Henderson  exit_mmap:
3484c7f17e7bSRichard Henderson     error_setg_errno(&err, errno, "Error mapping file");
3485c7f17e7bSRichard Henderson     goto exit_errmsg;
34868e62a717SRichard Henderson  exit_errmsg:
3487c7f17e7bSRichard Henderson     error_reportf_err(err, "%s: ", image_name);
34888e62a717SRichard Henderson     exit(-1);
34898e62a717SRichard Henderson }
34908e62a717SRichard Henderson 
34918e62a717SRichard Henderson static void load_elf_interp(const char *filename, struct image_info *info,
34928e62a717SRichard Henderson                             char bprm_buf[BPRM_BUF_SIZE])
34938e62a717SRichard Henderson {
349440d487eeSRichard Henderson     struct elfhdr ehdr;
34953bd02386SRichard Henderson     ImageSource src;
34968e62a717SRichard Henderson     int fd, retval;
3497808f6563SRichard Henderson     Error *err = NULL;
34988e62a717SRichard Henderson 
34998e62a717SRichard Henderson     fd = open(path(filename), O_RDONLY);
35008e62a717SRichard Henderson     if (fd < 0) {
3501808f6563SRichard Henderson         error_setg_file_open(&err, errno, filename);
3502808f6563SRichard Henderson         error_report_err(err);
3503808f6563SRichard Henderson         exit(-1);
35048e62a717SRichard Henderson     }
35058e62a717SRichard Henderson 
35068e62a717SRichard Henderson     retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
35078e62a717SRichard Henderson     if (retval < 0) {
3508808f6563SRichard Henderson         error_setg_errno(&err, errno, "Error reading file header");
3509808f6563SRichard Henderson         error_reportf_err(err, "%s: ", filename);
3510808f6563SRichard Henderson         exit(-1);
35118e62a717SRichard Henderson     }
3512808f6563SRichard Henderson 
35133bd02386SRichard Henderson     src.fd = fd;
35143bd02386SRichard Henderson     src.cache = bprm_buf;
35153bd02386SRichard Henderson     src.cache_size = retval;
35168e62a717SRichard Henderson 
35173bd02386SRichard Henderson     load_elf_image(filename, &src, info, &ehdr, NULL);
35188e62a717SRichard Henderson }
35198e62a717SRichard Henderson 
3520c40f621aSRichard Henderson #ifdef VDSO_HEADER
3521c40f621aSRichard Henderson #include VDSO_HEADER
3522c40f621aSRichard Henderson #define  vdso_image_info()  &vdso_image_info
3523c40f621aSRichard Henderson #else
3524c40f621aSRichard Henderson #define  vdso_image_info()  NULL
3525c40f621aSRichard Henderson #endif
3526c40f621aSRichard Henderson 
3527c40f621aSRichard Henderson static void load_elf_vdso(struct image_info *info, const VdsoImageInfo *vdso)
3528c40f621aSRichard Henderson {
3529c40f621aSRichard Henderson     ImageSource src;
3530c40f621aSRichard Henderson     struct elfhdr ehdr;
3531c40f621aSRichard Henderson     abi_ulong load_bias, load_addr;
3532c40f621aSRichard Henderson 
3533c40f621aSRichard Henderson     src.fd = -1;
3534c40f621aSRichard Henderson     src.cache = vdso->image;
3535c40f621aSRichard Henderson     src.cache_size = vdso->image_size;
3536c40f621aSRichard Henderson 
3537c40f621aSRichard Henderson     load_elf_image("<internal-vdso>", &src, info, &ehdr, NULL);
3538c40f621aSRichard Henderson     load_addr = info->load_addr;
3539c40f621aSRichard Henderson     load_bias = info->load_bias;
3540c40f621aSRichard Henderson 
3541c40f621aSRichard Henderson     /*
3542c40f621aSRichard Henderson      * We need to relocate the VDSO image.  The one built into the kernel
3543c40f621aSRichard Henderson      * is built for a fixed address.  The one built for QEMU is not, since
3544c40f621aSRichard Henderson      * that requires close control of the guest address space.
3545c40f621aSRichard Henderson      * We pre-processed the image to locate all of the addresses that need
3546c40f621aSRichard Henderson      * to be updated.
3547c40f621aSRichard Henderson      */
3548c40f621aSRichard Henderson     for (unsigned i = 0, n = vdso->reloc_count; i < n; i++) {
3549c40f621aSRichard Henderson         abi_ulong *addr = g2h_untagged(load_addr + vdso->relocs[i]);
3550c40f621aSRichard Henderson         *addr = tswapal(tswapal(*addr) + load_bias);
3551c40f621aSRichard Henderson     }
3552c40f621aSRichard Henderson 
3553c40f621aSRichard Henderson     /* Install signal trampolines, if present. */
3554c40f621aSRichard Henderson     if (vdso->sigreturn_ofs) {
3555c40f621aSRichard Henderson         default_sigreturn = load_addr + vdso->sigreturn_ofs;
3556c40f621aSRichard Henderson     }
3557c40f621aSRichard Henderson     if (vdso->rt_sigreturn_ofs) {
3558c40f621aSRichard Henderson         default_rt_sigreturn = load_addr + vdso->rt_sigreturn_ofs;
3559c40f621aSRichard Henderson     }
3560c40f621aSRichard Henderson 
3561c40f621aSRichard Henderson     /* Remove write from VDSO segment. */
3562c40f621aSRichard Henderson     target_mprotect(info->start_data, info->end_data - info->start_data,
3563c40f621aSRichard Henderson                     PROT_READ | PROT_EXEC);
356431e31b8aSbellard }
356531e31b8aSbellard 
356649918a75Spbrook static int symfind(const void *s0, const void *s1)
356749918a75Spbrook {
356849918a75Spbrook     struct elf_sym *sym = (struct elf_sym *)s1;
3569b6235a75SRichard Henderson     __typeof(sym->st_value) addr = *(uint64_t *)s0;
357049918a75Spbrook     int result = 0;
3571b6235a75SRichard Henderson 
3572c7c530cdSStefan Weil     if (addr < sym->st_value) {
357349918a75Spbrook         result = -1;
3574c7c530cdSStefan Weil     } else if (addr >= sym->st_value + sym->st_size) {
357549918a75Spbrook         result = 1;
357649918a75Spbrook     }
357749918a75Spbrook     return result;
357849918a75Spbrook }
357949918a75Spbrook 
3580b6235a75SRichard Henderson static const char *lookup_symbolxx(struct syminfo *s, uint64_t orig_addr)
358149918a75Spbrook {
358249918a75Spbrook #if ELF_CLASS == ELFCLASS32
358349918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf32;
358449918a75Spbrook #else
358549918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf64;
358649918a75Spbrook #endif
358749918a75Spbrook 
358849918a75Spbrook     // binary search
358949918a75Spbrook     struct elf_sym *sym;
359049918a75Spbrook 
3591c7c530cdSStefan Weil     sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
35927cba04f6SBlue Swirl     if (sym != NULL) {
359349918a75Spbrook         return s->disas_strtab + sym->st_name;
359449918a75Spbrook     }
359549918a75Spbrook 
359649918a75Spbrook     return "";
359749918a75Spbrook }
359849918a75Spbrook 
3599159fb790SPhilippe Mathieu-Daudé /* FIXME: This should use elf_ops.h.inc  */
360049918a75Spbrook static int symcmp(const void *s0, const void *s1)
360149918a75Spbrook {
360249918a75Spbrook     struct elf_sym *sym0 = (struct elf_sym *)s0;
360349918a75Spbrook     struct elf_sym *sym1 = (struct elf_sym *)s1;
360449918a75Spbrook     return (sym0->st_value < sym1->st_value)
360549918a75Spbrook         ? -1
360649918a75Spbrook         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
360749918a75Spbrook }
360849918a75Spbrook 
3609689f936fSbellard /* Best attempt to load symbols from this ELF object. */
361086cf82dcSRichard Henderson static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
361186cf82dcSRichard Henderson                          abi_ulong load_bias)
3612689f936fSbellard {
3613682674b8SRichard Henderson     int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
361486cf82dcSRichard Henderson     g_autofree struct elf_shdr *shdr = NULL;
3615b9475279SCédric VINCENT     char *strings = NULL;
361686cf82dcSRichard Henderson     struct elf_sym *syms = NULL;
361786cf82dcSRichard Henderson     struct elf_sym *new_syms;
361886cf82dcSRichard Henderson     uint64_t segsz;
361931e31b8aSbellard 
3620682674b8SRichard Henderson     shnum = hdr->e_shnum;
362186cf82dcSRichard Henderson     shdr = imgsrc_read_alloc(hdr->e_shoff, shnum * sizeof(struct elf_shdr),
362286cf82dcSRichard Henderson                              src, NULL);
362386cf82dcSRichard Henderson     if (shdr == NULL) {
3624689f936fSbellard         return;
3625682674b8SRichard Henderson     }
3626682674b8SRichard Henderson 
3627682674b8SRichard Henderson     bswap_shdr(shdr, shnum);
3628682674b8SRichard Henderson     for (i = 0; i < shnum; ++i) {
3629682674b8SRichard Henderson         if (shdr[i].sh_type == SHT_SYMTAB) {
3630682674b8SRichard Henderson             sym_idx = i;
3631682674b8SRichard Henderson             str_idx = shdr[i].sh_link;
3632689f936fSbellard             goto found;
3633689f936fSbellard         }
3634689f936fSbellard     }
3635682674b8SRichard Henderson 
3636682674b8SRichard Henderson     /* There will be no symbol table if the file was stripped.  */
3637682674b8SRichard Henderson     return;
3638689f936fSbellard 
3639689f936fSbellard  found:
3640689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them.  */
3641682674b8SRichard Henderson 
36421e06262dSPeter Maydell     segsz = shdr[str_idx].sh_size;
364386cf82dcSRichard Henderson     strings = g_try_malloc(segsz);
364486cf82dcSRichard Henderson     if (!strings) {
364586cf82dcSRichard Henderson         goto give_up;
364686cf82dcSRichard Henderson     }
364786cf82dcSRichard Henderson     if (!imgsrc_read(strings, shdr[str_idx].sh_offset, segsz, src, NULL)) {
3648b9475279SCédric VINCENT         goto give_up;
3649682674b8SRichard Henderson     }
3650689f936fSbellard 
36511e06262dSPeter Maydell     segsz = shdr[sym_idx].sh_size;
36521e06262dSPeter Maydell     if (segsz / sizeof(struct elf_sym) > INT_MAX) {
365386cf82dcSRichard Henderson         /*
365486cf82dcSRichard Henderson          * Implausibly large symbol table: give up rather than ploughing
365586cf82dcSRichard Henderson          * on with the number of symbols calculation overflowing.
36561e06262dSPeter Maydell          */
36571e06262dSPeter Maydell         goto give_up;
36581e06262dSPeter Maydell     }
36591e06262dSPeter Maydell     nsyms = segsz / sizeof(struct elf_sym);
366086cf82dcSRichard Henderson     syms = g_try_malloc(segsz);
366186cf82dcSRichard Henderson     if (!syms) {
366286cf82dcSRichard Henderson         goto give_up;
366386cf82dcSRichard Henderson     }
366486cf82dcSRichard Henderson     if (!imgsrc_read(syms, shdr[sym_idx].sh_offset, segsz, src, NULL)) {
366586cf82dcSRichard Henderson         goto give_up;
366686cf82dcSRichard Henderson     }
366786cf82dcSRichard Henderson 
3668682674b8SRichard Henderson     for (i = 0; i < nsyms; ) {
366949918a75Spbrook         bswap_sym(syms + i);
3670682674b8SRichard Henderson         /* Throw away entries which we do not need.  */
3671682674b8SRichard Henderson         if (syms[i].st_shndx == SHN_UNDEF
3672682674b8SRichard Henderson             || syms[i].st_shndx >= SHN_LORESERVE
3673682674b8SRichard Henderson             || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
3674682674b8SRichard Henderson             if (i < --nsyms) {
367549918a75Spbrook                 syms[i] = syms[nsyms];
367649918a75Spbrook             }
3677682674b8SRichard Henderson         } else {
367849918a75Spbrook #if defined(TARGET_ARM) || defined (TARGET_MIPS)
367949918a75Spbrook             /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
368049918a75Spbrook             syms[i].st_value &= ~(target_ulong)1;
368149918a75Spbrook #endif
3682682674b8SRichard Henderson             syms[i].st_value += load_bias;
368349918a75Spbrook             i++;
368449918a75Spbrook         }
3685682674b8SRichard Henderson     }
368649918a75Spbrook 
3687b9475279SCédric VINCENT     /* No "useful" symbol.  */
3688b9475279SCédric VINCENT     if (nsyms == 0) {
3689b9475279SCédric VINCENT         goto give_up;
3690b9475279SCédric VINCENT     }
3691b9475279SCédric VINCENT 
369286cf82dcSRichard Henderson     /*
369386cf82dcSRichard Henderson      * Attempt to free the storage associated with the local symbols
369486cf82dcSRichard Henderson      * that we threw away.  Whether or not this has any effect on the
369586cf82dcSRichard Henderson      * memory allocation depends on the malloc implementation and how
369686cf82dcSRichard Henderson      * many symbols we managed to discard.
369786cf82dcSRichard Henderson      */
36980ef9ea29SPeter Maydell     new_syms = g_try_renew(struct elf_sym, syms, nsyms);
36998d79de6eSStefan Weil     if (new_syms == NULL) {
3700b9475279SCédric VINCENT         goto give_up;
37015d5c9930SRichard Henderson     }
37028d79de6eSStefan Weil     syms = new_syms;
37035d5c9930SRichard Henderson 
370449918a75Spbrook     qsort(syms, nsyms, sizeof(*syms), symcmp);
370549918a75Spbrook 
370686cf82dcSRichard Henderson     {
370786cf82dcSRichard Henderson         struct syminfo *s = g_new(struct syminfo, 1);
370886cf82dcSRichard Henderson 
370986cf82dcSRichard Henderson         s->disas_strtab = strings;
371049918a75Spbrook         s->disas_num_syms = nsyms;
371149918a75Spbrook #if ELF_CLASS == ELFCLASS32
371249918a75Spbrook         s->disas_symtab.elf32 = syms;
371349918a75Spbrook #else
371449918a75Spbrook         s->disas_symtab.elf64 = syms;
371549918a75Spbrook #endif
3716682674b8SRichard Henderson         s->lookup_symbol = lookup_symbolxx;
3717e80cfcfcSbellard         s->next = syminfos;
3718e80cfcfcSbellard         syminfos = s;
371986cf82dcSRichard Henderson     }
3720b9475279SCédric VINCENT     return;
3721b9475279SCédric VINCENT 
3722b9475279SCédric VINCENT  give_up:
37230ef9ea29SPeter Maydell     g_free(strings);
37240ef9ea29SPeter Maydell     g_free(syms);
3725689f936fSbellard }
372631e31b8aSbellard 
3727768fe76eSYunQiang Su uint32_t get_elf_eflags(int fd)
3728768fe76eSYunQiang Su {
3729768fe76eSYunQiang Su     struct elfhdr ehdr;
3730768fe76eSYunQiang Su     off_t offset;
3731768fe76eSYunQiang Su     int ret;
3732768fe76eSYunQiang Su 
3733768fe76eSYunQiang Su     /* Read ELF header */
3734768fe76eSYunQiang Su     offset = lseek(fd, 0, SEEK_SET);
3735768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3736768fe76eSYunQiang Su         return 0;
3737768fe76eSYunQiang Su     }
3738768fe76eSYunQiang Su     ret = read(fd, &ehdr, sizeof(ehdr));
3739768fe76eSYunQiang Su     if (ret < sizeof(ehdr)) {
3740768fe76eSYunQiang Su         return 0;
3741768fe76eSYunQiang Su     }
3742768fe76eSYunQiang Su     offset = lseek(fd, offset, SEEK_SET);
3743768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3744768fe76eSYunQiang Su         return 0;
3745768fe76eSYunQiang Su     }
3746768fe76eSYunQiang Su 
3747768fe76eSYunQiang Su     /* Check ELF signature */
3748768fe76eSYunQiang Su     if (!elf_check_ident(&ehdr)) {
3749768fe76eSYunQiang Su         return 0;
3750768fe76eSYunQiang Su     }
3751768fe76eSYunQiang Su 
3752768fe76eSYunQiang Su     /* check header */
3753768fe76eSYunQiang Su     bswap_ehdr(&ehdr);
3754768fe76eSYunQiang Su     if (!elf_check_ehdr(&ehdr)) {
3755768fe76eSYunQiang Su         return 0;
3756768fe76eSYunQiang Su     }
3757768fe76eSYunQiang Su 
3758768fe76eSYunQiang Su     /* return architecture id */
3759768fe76eSYunQiang Su     return ehdr.e_flags;
3760768fe76eSYunQiang Su }
3761768fe76eSYunQiang Su 
3762f0116c54SWill Newton int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
376331e31b8aSbellard {
376440d487eeSRichard Henderson     /*
376540d487eeSRichard Henderson      * We need a copy of the elf header for passing to create_elf_tables.
376640d487eeSRichard Henderson      * We will have overwritten the original when we re-use bprm->buf
376740d487eeSRichard Henderson      * while loading the interpreter.  Allocate the storage for this now
376840d487eeSRichard Henderson      * and let elf_load_image do any swapping that may be required.
376940d487eeSRichard Henderson      */
377040d487eeSRichard Henderson     struct elfhdr ehdr;
3771c40f621aSRichard Henderson     struct image_info interp_info, vdso_info;
37728e62a717SRichard Henderson     char *elf_interpreter = NULL;
377359baae9aSStefan Brüns     char *scratch;
377431e31b8aSbellard 
3775abcac736SDaniel Santos     memset(&interp_info, 0, sizeof(interp_info));
3776abcac736SDaniel Santos #ifdef TARGET_MIPS
3777abcac736SDaniel Santos     interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
3778abcac736SDaniel Santos #endif
3779abcac736SDaniel Santos 
37803bd02386SRichard Henderson     load_elf_image(bprm->filename, &bprm->src, info, &ehdr, &elf_interpreter);
378131e31b8aSbellard 
378259baae9aSStefan Brüns     /* Do this so that we can load the interpreter, if need be.  We will
378359baae9aSStefan Brüns        change some of these later */
378459baae9aSStefan Brüns     bprm->p = setup_arg_pages(bprm, info);
378559baae9aSStefan Brüns 
378659baae9aSStefan Brüns     scratch = g_new0(char, TARGET_PAGE_SIZE);
37877c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
378859baae9aSStefan Brüns         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
378959baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
37907c4ee5bcSRichard Henderson         info->file_string = bprm->p;
379159baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
379259baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
37937c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
379459baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
379559baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
37967c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
37977c4ee5bcSRichard Henderson     } else {
37987c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
37997c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
38007c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
38017c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
38027c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
38037c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
38047c4ee5bcSRichard Henderson         info->file_string = bprm->p;
38057c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
38067c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
38077c4ee5bcSRichard Henderson     }
38087c4ee5bcSRichard Henderson 
380959baae9aSStefan Brüns     g_free(scratch);
381059baae9aSStefan Brüns 
3811e5fe0c52Spbrook     if (!bprm->p) {
3812bf858897SRichard Henderson         fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
381331e31b8aSbellard         exit(-1);
38149955ffacSRichard Henderson     }
3815379f6698SPaul Brook 
38168e62a717SRichard Henderson     if (elf_interpreter) {
38178e62a717SRichard Henderson         load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
381831e31b8aSbellard 
38191f356e8cSHelge Deller         /*
38201f356e8cSHelge Deller          * While unusual because of ELF_ET_DYN_BASE, if we are unlucky
38211f356e8cSHelge Deller          * with the mappings the interpreter can be loaded above but
38221f356e8cSHelge Deller          * near the main executable, which can leave very little room
38231f356e8cSHelge Deller          * for the heap.
38241f356e8cSHelge Deller          * If the current brk has less than 16MB, use the end of the
38251f356e8cSHelge Deller          * interpreter.
38261f356e8cSHelge Deller          */
38271f356e8cSHelge Deller         if (interp_info.brk > info->brk &&
38281f356e8cSHelge Deller             interp_info.load_bias - info->brk < 16 * MiB)  {
38291f356e8cSHelge Deller             info->brk = interp_info.brk;
38301f356e8cSHelge Deller         }
38311f356e8cSHelge Deller 
38328e62a717SRichard Henderson         /* If the program interpreter is one of these two, then assume
38338e62a717SRichard Henderson            an iBCS2 image.  Otherwise assume a native linux image.  */
383431e31b8aSbellard 
38358e62a717SRichard Henderson         if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
38368e62a717SRichard Henderson             || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
38378e62a717SRichard Henderson             info->personality = PER_SVR4;
38388e62a717SRichard Henderson 
383931e31b8aSbellard             /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
38408e62a717SRichard Henderson                and some applications "depend" upon this behavior.  Since
38418e62a717SRichard Henderson                we do not have the power to recompile these, we emulate
38428e62a717SRichard Henderson                the SVr4 behavior.  Sigh.  */
3843f11c05c3SRichard Henderson             target_mmap(0, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC,
3844f11c05c3SRichard Henderson                         MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS,
3845f11c05c3SRichard Henderson                         -1, 0);
384631e31b8aSbellard         }
3847c94cb6c9SStefan Markovic #ifdef TARGET_MIPS
3848c94cb6c9SStefan Markovic         info->interp_fp_abi = interp_info.fp_abi;
3849c94cb6c9SStefan Markovic #endif
38508e62a717SRichard Henderson     }
385131e31b8aSbellard 
3852db2af69dSRichard Henderson     /*
3853c40f621aSRichard Henderson      * Load a vdso if available, which will amongst other things contain the
3854c40f621aSRichard Henderson      * signal trampolines.  Otherwise, allocate a separate page for them.
3855db2af69dSRichard Henderson      */
3856c40f621aSRichard Henderson     const VdsoImageInfo *vdso = vdso_image_info();
3857c40f621aSRichard Henderson     if (vdso) {
3858c40f621aSRichard Henderson         load_elf_vdso(&vdso_info, vdso);
38595d94c2ffSRichard Henderson         info->vdso = vdso_info.load_bias;
3860c40f621aSRichard Henderson     } else if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
3861802ae45eSLaurent Vivier         abi_long tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
3862db2af69dSRichard Henderson                                           PROT_READ | PROT_WRITE,
3863db2af69dSRichard Henderson                                           MAP_PRIVATE | MAP_ANON, -1, 0);
3864802ae45eSLaurent Vivier         if (tramp_page == -1) {
3865802ae45eSLaurent Vivier             return -errno;
3866802ae45eSLaurent Vivier         }
3867802ae45eSLaurent Vivier 
3868db2af69dSRichard Henderson         setup_sigtramp(tramp_page);
3869db2af69dSRichard Henderson         target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
3870db2af69dSRichard Henderson     }
3871db2af69dSRichard Henderson 
3872c40f621aSRichard Henderson     bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &ehdr, info,
3873c40f621aSRichard Henderson                                 elf_interpreter ? &interp_info : NULL,
3874c40f621aSRichard Henderson                                 vdso ? &vdso_info : NULL);
38758e62a717SRichard Henderson     info->start_stack = bprm->p;
38768e62a717SRichard Henderson 
38778e62a717SRichard Henderson     /* If we have an interpreter, set that as the program's entry point.
38788e78064eSRichard Henderson        Copy the load_bias as well, to help PPC64 interpret the entry
38798e62a717SRichard Henderson        point as a function descriptor.  Do this after creating elf tables
38808e62a717SRichard Henderson        so that we copy the original program entry point into the AUXV.  */
38818e62a717SRichard Henderson     if (elf_interpreter) {
38828e78064eSRichard Henderson         info->load_bias = interp_info.load_bias;
38838e62a717SRichard Henderson         info->entry = interp_info.entry;
38842b323087SPhilippe Mathieu-Daudé         g_free(elf_interpreter);
38858e62a717SRichard Henderson     }
388631e31b8aSbellard 
3887edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3888edf8e2afSMika Westerberg     bprm->core_dump = &elf_core_dump;
3889edf8e2afSMika Westerberg #endif
3890edf8e2afSMika Westerberg 
389131e31b8aSbellard     return 0;
389231e31b8aSbellard }
389331e31b8aSbellard 
3894edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
389541689bb3SRichard Henderson #include "exec/translate-all.h"
389641689bb3SRichard Henderson 
3897edf8e2afSMika Westerberg /*
3898edf8e2afSMika Westerberg  * Definitions to generate Intel SVR4-like core files.
3899a2547a13SLaurent Desnogues  * These mostly have the same names as the SVR4 types with "target_elf_"
3900edf8e2afSMika Westerberg  * tacked on the front to prevent clashes with linux definitions,
3901edf8e2afSMika Westerberg  * and the typedef forms have been avoided.  This is mostly like
3902edf8e2afSMika Westerberg  * the SVR4 structure, but more Linuxy, with things that Linux does
3903edf8e2afSMika Westerberg  * not support and which gdb doesn't really use excluded.
3904edf8e2afSMika Westerberg  *
3905edf8e2afSMika Westerberg  * Fields we don't dump (their contents is zero) in linux-user qemu
3906edf8e2afSMika Westerberg  * are marked with XXX.
3907edf8e2afSMika Westerberg  *
3908edf8e2afSMika Westerberg  * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
3909edf8e2afSMika Westerberg  *
3910edf8e2afSMika Westerberg  * Porting ELF coredump for target is (quite) simple process.  First you
3911dd0a3651SNathan Froyd  * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
3912edf8e2afSMika Westerberg  * the target resides):
3913edf8e2afSMika Westerberg  *
3914edf8e2afSMika Westerberg  * #define USE_ELF_CORE_DUMP
3915edf8e2afSMika Westerberg  *
3916edf8e2afSMika Westerberg  * Next you define type of register set used for dumping.  ELF specification
3917edf8e2afSMika Westerberg  * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
3918edf8e2afSMika Westerberg  *
3919c227f099SAnthony Liguori  * typedef <target_regtype> target_elf_greg_t;
3920edf8e2afSMika Westerberg  * #define ELF_NREG <number of registers>
3921c227f099SAnthony Liguori  * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
3922edf8e2afSMika Westerberg  *
3923edf8e2afSMika Westerberg  * Last step is to implement target specific function that copies registers
3924edf8e2afSMika Westerberg  * from given cpu into just specified register set.  Prototype is:
3925edf8e2afSMika Westerberg  *
3926c227f099SAnthony Liguori  * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
39279349b4f9SAndreas Färber  *                                const CPUArchState *env);
3928edf8e2afSMika Westerberg  *
3929edf8e2afSMika Westerberg  * Parameters:
3930edf8e2afSMika Westerberg  *     regs - copy register values into here (allocated and zeroed by caller)
3931edf8e2afSMika Westerberg  *     env - copy registers from here
3932edf8e2afSMika Westerberg  *
3933edf8e2afSMika Westerberg  * Example for ARM target is provided in this file.
3934edf8e2afSMika Westerberg  */
3935edf8e2afSMika Westerberg 
3936a2547a13SLaurent Desnogues struct target_elf_siginfo {
3937f8fd4fc4SPaolo Bonzini     abi_int    si_signo; /* signal number */
3938f8fd4fc4SPaolo Bonzini     abi_int    si_code;  /* extra code */
3939f8fd4fc4SPaolo Bonzini     abi_int    si_errno; /* errno */
3940edf8e2afSMika Westerberg };
3941edf8e2afSMika Westerberg 
3942a2547a13SLaurent Desnogues struct target_elf_prstatus {
3943a2547a13SLaurent Desnogues     struct target_elf_siginfo pr_info;      /* Info associated with signal */
39441ddd592fSPaolo Bonzini     abi_short          pr_cursig;    /* Current signal */
3945ca98ac83SPaolo Bonzini     abi_ulong          pr_sigpend;   /* XXX */
3946ca98ac83SPaolo Bonzini     abi_ulong          pr_sighold;   /* XXX */
3947c227f099SAnthony Liguori     target_pid_t       pr_pid;
3948c227f099SAnthony Liguori     target_pid_t       pr_ppid;
3949c227f099SAnthony Liguori     target_pid_t       pr_pgrp;
3950c227f099SAnthony Liguori     target_pid_t       pr_sid;
3951edf8e2afSMika Westerberg     struct target_timeval pr_utime;  /* XXX User time */
3952edf8e2afSMika Westerberg     struct target_timeval pr_stime;  /* XXX System time */
3953edf8e2afSMika Westerberg     struct target_timeval pr_cutime; /* XXX Cumulative user time */
3954edf8e2afSMika Westerberg     struct target_timeval pr_cstime; /* XXX Cumulative system time */
3955c227f099SAnthony Liguori     target_elf_gregset_t      pr_reg;       /* GP registers */
3956f8fd4fc4SPaolo Bonzini     abi_int            pr_fpvalid;   /* XXX */
3957edf8e2afSMika Westerberg };
3958edf8e2afSMika Westerberg 
3959edf8e2afSMika Westerberg #define ELF_PRARGSZ     (80) /* Number of chars for args */
3960edf8e2afSMika Westerberg 
3961a2547a13SLaurent Desnogues struct target_elf_prpsinfo {
3962edf8e2afSMika Westerberg     char         pr_state;       /* numeric process state */
3963edf8e2afSMika Westerberg     char         pr_sname;       /* char for pr_state */
3964edf8e2afSMika Westerberg     char         pr_zomb;        /* zombie */
3965edf8e2afSMika Westerberg     char         pr_nice;        /* nice val */
3966ca98ac83SPaolo Bonzini     abi_ulong    pr_flag;        /* flags */
3967c227f099SAnthony Liguori     target_uid_t pr_uid;
3968c227f099SAnthony Liguori     target_gid_t pr_gid;
3969c227f099SAnthony Liguori     target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
3970edf8e2afSMika Westerberg     /* Lots missing */
3971d7eb2b92SAlistair Francis     char    pr_fname[16] QEMU_NONSTRING; /* filename of executable */
3972edf8e2afSMika Westerberg     char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
3973edf8e2afSMika Westerberg };
3974edf8e2afSMika Westerberg 
3975edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
3976a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *prstatus)
3977edf8e2afSMika Westerberg {
3978ca98ac83SPaolo Bonzini     prstatus->pr_info.si_signo = tswap32(prstatus->pr_info.si_signo);
3979ca98ac83SPaolo Bonzini     prstatus->pr_info.si_code = tswap32(prstatus->pr_info.si_code);
3980ca98ac83SPaolo Bonzini     prstatus->pr_info.si_errno = tswap32(prstatus->pr_info.si_errno);
3981edf8e2afSMika Westerberg     prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
3982ca98ac83SPaolo Bonzini     prstatus->pr_sigpend = tswapal(prstatus->pr_sigpend);
3983ca98ac83SPaolo Bonzini     prstatus->pr_sighold = tswapal(prstatus->pr_sighold);
3984edf8e2afSMika Westerberg     prstatus->pr_pid = tswap32(prstatus->pr_pid);
3985edf8e2afSMika Westerberg     prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
3986edf8e2afSMika Westerberg     prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
3987edf8e2afSMika Westerberg     prstatus->pr_sid = tswap32(prstatus->pr_sid);
3988edf8e2afSMika Westerberg     /* cpu times are not filled, so we skip them */
3989edf8e2afSMika Westerberg     /* regs should be in correct format already */
3990edf8e2afSMika Westerberg     prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
3991edf8e2afSMika Westerberg }
3992edf8e2afSMika Westerberg 
3993a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
3994edf8e2afSMika Westerberg {
3995ca98ac83SPaolo Bonzini     psinfo->pr_flag = tswapal(psinfo->pr_flag);
3996edf8e2afSMika Westerberg     psinfo->pr_uid = tswap16(psinfo->pr_uid);
3997edf8e2afSMika Westerberg     psinfo->pr_gid = tswap16(psinfo->pr_gid);
3998edf8e2afSMika Westerberg     psinfo->pr_pid = tswap32(psinfo->pr_pid);
3999edf8e2afSMika Westerberg     psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
4000edf8e2afSMika Westerberg     psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
4001edf8e2afSMika Westerberg     psinfo->pr_sid = tswap32(psinfo->pr_sid);
4002edf8e2afSMika Westerberg }
4003991f8f0cSRichard Henderson 
4004991f8f0cSRichard Henderson static void bswap_note(struct elf_note *en)
4005991f8f0cSRichard Henderson {
4006991f8f0cSRichard Henderson     bswap32s(&en->n_namesz);
4007991f8f0cSRichard Henderson     bswap32s(&en->n_descsz);
4008991f8f0cSRichard Henderson     bswap32s(&en->n_type);
4009991f8f0cSRichard Henderson }
4010991f8f0cSRichard Henderson #else
4011991f8f0cSRichard Henderson static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
4012991f8f0cSRichard Henderson static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
4013991f8f0cSRichard Henderson static inline void bswap_note(struct elf_note *en) { }
4014edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
4015edf8e2afSMika Westerberg 
4016edf8e2afSMika Westerberg /*
4017edf8e2afSMika Westerberg  * Calculate file (dump) size of given memory region.
4018edf8e2afSMika Westerberg  */
401950e33f52SRichard Henderson static size_t vma_dump_size(target_ulong start, target_ulong end,
402050e33f52SRichard Henderson                             unsigned long flags)
4021edf8e2afSMika Westerberg {
40221928d50bSRichard Henderson     /* The area must be readable. */
402350e33f52SRichard Henderson     if (!(flags & PAGE_READ)) {
40241928d50bSRichard Henderson         return 0;
40251928d50bSRichard Henderson     }
4026edf8e2afSMika Westerberg 
4027edf8e2afSMika Westerberg     /*
4028edf8e2afSMika Westerberg      * Usually we don't dump executable pages as they contain
4029edf8e2afSMika Westerberg      * non-writable code that debugger can read directly from
40301928d50bSRichard Henderson      * target library etc. If there is no elf header, we dump it.
4031edf8e2afSMika Westerberg      */
403250e33f52SRichard Henderson     if (!(flags & PAGE_WRITE_ORG) &&
403350e33f52SRichard Henderson         (flags & PAGE_EXEC) &&
403450e33f52SRichard Henderson         memcmp(g2h_untagged(start), ELFMAG, SELFMAG) == 0) {
4035022625a8SPeter Maydell         return 0;
4036022625a8SPeter Maydell     }
4037edf8e2afSMika Westerberg 
403850e33f52SRichard Henderson     return end - start;
4039edf8e2afSMika Westerberg }
4040edf8e2afSMika Westerberg 
40412410d28dSRichard Henderson static size_t size_note(const char *name, size_t datasz)
40422410d28dSRichard Henderson {
40432410d28dSRichard Henderson     size_t namesz = strlen(name) + 1;
40442410d28dSRichard Henderson 
40452410d28dSRichard Henderson     namesz = ROUND_UP(namesz, 4);
40462410d28dSRichard Henderson     datasz = ROUND_UP(datasz, 4);
40472410d28dSRichard Henderson 
40482410d28dSRichard Henderson     return sizeof(struct elf_note) + namesz + datasz;
40492410d28dSRichard Henderson }
40502410d28dSRichard Henderson 
4051243c4706SRichard Henderson static void *fill_note(void **pptr, int type, const char *name, size_t datasz)
4052edf8e2afSMika Westerberg {
4053243c4706SRichard Henderson     void *ptr = *pptr;
4054243c4706SRichard Henderson     struct elf_note *n = ptr;
4055243c4706SRichard Henderson     size_t namesz = strlen(name) + 1;
4056edf8e2afSMika Westerberg 
4057243c4706SRichard Henderson     n->n_namesz = namesz;
4058243c4706SRichard Henderson     n->n_descsz = datasz;
4059243c4706SRichard Henderson     n->n_type = type;
4060243c4706SRichard Henderson     bswap_note(n);
406180f5ce75SLaurent Vivier 
4062243c4706SRichard Henderson     ptr += sizeof(*n);
4063243c4706SRichard Henderson     memcpy(ptr, name, namesz);
4064edf8e2afSMika Westerberg 
4065243c4706SRichard Henderson     namesz = ROUND_UP(namesz, 4);
4066243c4706SRichard Henderson     datasz = ROUND_UP(datasz, 4);
4067243c4706SRichard Henderson 
4068243c4706SRichard Henderson     *pptr = ptr + namesz + datasz;
4069243c4706SRichard Henderson     return ptr + namesz;
4070edf8e2afSMika Westerberg }
4071edf8e2afSMika Westerberg 
4072edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
4073edf8e2afSMika Westerberg                             uint32_t flags)
4074edf8e2afSMika Westerberg {
4075243c4706SRichard Henderson     memcpy(elf->e_ident, ELFMAG, SELFMAG);
4076edf8e2afSMika Westerberg 
4077edf8e2afSMika Westerberg     elf->e_ident[EI_CLASS] = ELF_CLASS;
4078edf8e2afSMika Westerberg     elf->e_ident[EI_DATA] = ELF_DATA;
4079edf8e2afSMika Westerberg     elf->e_ident[EI_VERSION] = EV_CURRENT;
4080edf8e2afSMika Westerberg     elf->e_ident[EI_OSABI] = ELF_OSABI;
4081edf8e2afSMika Westerberg 
4082edf8e2afSMika Westerberg     elf->e_type = ET_CORE;
4083edf8e2afSMika Westerberg     elf->e_machine = machine;
4084edf8e2afSMika Westerberg     elf->e_version = EV_CURRENT;
4085edf8e2afSMika Westerberg     elf->e_phoff = sizeof(struct elfhdr);
4086edf8e2afSMika Westerberg     elf->e_flags = flags;
4087edf8e2afSMika Westerberg     elf->e_ehsize = sizeof(struct elfhdr);
4088edf8e2afSMika Westerberg     elf->e_phentsize = sizeof(struct elf_phdr);
4089edf8e2afSMika Westerberg     elf->e_phnum = segs;
4090edf8e2afSMika Westerberg 
4091edf8e2afSMika Westerberg     bswap_ehdr(elf);
4092edf8e2afSMika Westerberg }
4093edf8e2afSMika Westerberg 
4094243c4706SRichard Henderson static void fill_elf_note_phdr(struct elf_phdr *phdr, size_t sz, off_t offset)
4095edf8e2afSMika Westerberg {
4096edf8e2afSMika Westerberg     phdr->p_type = PT_NOTE;
4097edf8e2afSMika Westerberg     phdr->p_offset = offset;
4098edf8e2afSMika Westerberg     phdr->p_filesz = sz;
4099edf8e2afSMika Westerberg 
4100991f8f0cSRichard Henderson     bswap_phdr(phdr, 1);
4101edf8e2afSMika Westerberg }
4102edf8e2afSMika Westerberg 
4103243c4706SRichard Henderson static void fill_prstatus_note(void *data, const TaskState *ts,
4104243c4706SRichard Henderson                                CPUState *cpu, int signr)
4105edf8e2afSMika Westerberg {
4106243c4706SRichard Henderson     /*
4107243c4706SRichard Henderson      * Because note memory is only aligned to 4, and target_elf_prstatus
4108243c4706SRichard Henderson      * may well have higher alignment requirements, fill locally and
4109243c4706SRichard Henderson      * memcpy to the destination afterward.
4110243c4706SRichard Henderson      */
4111243c4706SRichard Henderson     struct target_elf_prstatus prstatus = {
4112243c4706SRichard Henderson         .pr_info.si_signo = signr,
4113243c4706SRichard Henderson         .pr_cursig = signr,
4114243c4706SRichard Henderson         .pr_pid = ts->ts_tid,
4115243c4706SRichard Henderson         .pr_ppid = getppid(),
4116243c4706SRichard Henderson         .pr_pgrp = getpgrp(),
4117243c4706SRichard Henderson         .pr_sid = getsid(0),
4118243c4706SRichard Henderson     };
4119243c4706SRichard Henderson 
4120243c4706SRichard Henderson     elf_core_copy_regs(&prstatus.pr_reg, cpu_env(cpu));
4121243c4706SRichard Henderson     bswap_prstatus(&prstatus);
4122243c4706SRichard Henderson     memcpy(data, &prstatus, sizeof(prstatus));
4123edf8e2afSMika Westerberg }
4124edf8e2afSMika Westerberg 
4125243c4706SRichard Henderson static void fill_prpsinfo_note(void *data, const TaskState *ts)
4126edf8e2afSMika Westerberg {
4127243c4706SRichard Henderson     /*
4128243c4706SRichard Henderson      * Because note memory is only aligned to 4, and target_elf_prpsinfo
4129243c4706SRichard Henderson      * may well have higher alignment requirements, fill locally and
4130243c4706SRichard Henderson      * memcpy to the destination afterward.
4131243c4706SRichard Henderson      */
413252e566b3SRichard Henderson     struct target_elf_prpsinfo psinfo = {
413352e566b3SRichard Henderson         .pr_pid = getpid(),
413452e566b3SRichard Henderson         .pr_ppid = getppid(),
413552e566b3SRichard Henderson         .pr_pgrp = getpgrp(),
413652e566b3SRichard Henderson         .pr_sid = getsid(0),
413752e566b3SRichard Henderson         .pr_uid = getuid(),
413852e566b3SRichard Henderson         .pr_gid = getgid(),
413952e566b3SRichard Henderson     };
4140900cfbcaSJim Meyering     char *base_filename;
4141243c4706SRichard Henderson     size_t len;
4142edf8e2afSMika Westerberg 
41435f779a3aSIlya Leoshkevich     len = ts->info->env_strings - ts->info->arg_strings;
4144243c4706SRichard Henderson     len = MIN(len, ELF_PRARGSZ);
4145243c4706SRichard Henderson     memcpy(&psinfo.pr_psargs, g2h_untagged(ts->info->arg_strings), len);
4146243c4706SRichard Henderson     for (size_t i = 0; i < len; i++) {
4147243c4706SRichard Henderson         if (psinfo.pr_psargs[i] == 0) {
4148243c4706SRichard Henderson             psinfo.pr_psargs[i] = ' ';
41495f779a3aSIlya Leoshkevich         }
4150243c4706SRichard Henderson     }
4151edf8e2afSMika Westerberg 
4152900cfbcaSJim Meyering     base_filename = g_path_get_basename(ts->bprm->filename);
4153900cfbcaSJim Meyering     /*
4154900cfbcaSJim Meyering      * Using strncpy here is fine: at max-length,
4155900cfbcaSJim Meyering      * this field is not NUL-terminated.
4156900cfbcaSJim Meyering      */
4157243c4706SRichard Henderson     strncpy(psinfo.pr_fname, base_filename, sizeof(psinfo.pr_fname));
4158900cfbcaSJim Meyering     g_free(base_filename);
4159243c4706SRichard Henderson 
4160243c4706SRichard Henderson     bswap_psinfo(&psinfo);
4161243c4706SRichard Henderson     memcpy(data, &psinfo, sizeof(psinfo));
4162edf8e2afSMika Westerberg }
4163edf8e2afSMika Westerberg 
4164243c4706SRichard Henderson static void fill_auxv_note(void *data, const TaskState *ts)
4165edf8e2afSMika Westerberg {
4166243c4706SRichard Henderson     memcpy(data, g2h_untagged(ts->info->saved_auxv), ts->info->auxv_len);
4167edf8e2afSMika Westerberg }
4168edf8e2afSMika Westerberg 
4169edf8e2afSMika Westerberg /*
4170edf8e2afSMika Westerberg  * Constructs name of coredump file.  We have following convention
4171edf8e2afSMika Westerberg  * for the name:
4172edf8e2afSMika Westerberg  *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
4173edf8e2afSMika Westerberg  *
417468af19adSDaniel P. Berrangé  * Returns the filename
4175edf8e2afSMika Westerberg  */
417668af19adSDaniel P. Berrangé static char *core_dump_filename(const TaskState *ts)
4177edf8e2afSMika Westerberg {
417868af19adSDaniel P. Berrangé     g_autoptr(GDateTime) now = g_date_time_new_now_local();
417968af19adSDaniel P. Berrangé     g_autofree char *nowstr = g_date_time_format(now, "%Y%m%d-%H%M%S");
418068af19adSDaniel P. Berrangé     g_autofree char *base_filename = g_path_get_basename(ts->bprm->filename);
4181edf8e2afSMika Westerberg 
418268af19adSDaniel P. Berrangé     return g_strdup_printf("qemu_%s_%s_%d.core",
418368af19adSDaniel P. Berrangé                            base_filename, nowstr, (int)getpid());
4184edf8e2afSMika Westerberg }
4185edf8e2afSMika Westerberg 
4186edf8e2afSMika Westerberg static int dump_write(int fd, const void *ptr, size_t size)
4187edf8e2afSMika Westerberg {
4188edf8e2afSMika Westerberg     const char *bufp = (const char *)ptr;
4189edf8e2afSMika Westerberg     ssize_t bytes_written, bytes_left;
4190edf8e2afSMika Westerberg 
4191edf8e2afSMika Westerberg     bytes_written = 0;
4192edf8e2afSMika Westerberg     bytes_left = size;
4193edf8e2afSMika Westerberg 
4194edf8e2afSMika Westerberg     /*
4195edf8e2afSMika Westerberg      * In normal conditions, single write(2) should do but
4196edf8e2afSMika Westerberg      * in case of socket etc. this mechanism is more portable.
4197edf8e2afSMika Westerberg      */
4198edf8e2afSMika Westerberg     do {
4199edf8e2afSMika Westerberg         bytes_written = write(fd, bufp, bytes_left);
4200edf8e2afSMika Westerberg         if (bytes_written < 0) {
4201edf8e2afSMika Westerberg             if (errno == EINTR)
4202edf8e2afSMika Westerberg                 continue;
4203edf8e2afSMika Westerberg             return (-1);
4204edf8e2afSMika Westerberg         } else if (bytes_written == 0) { /* eof */
4205edf8e2afSMika Westerberg             return (-1);
4206edf8e2afSMika Westerberg         }
4207edf8e2afSMika Westerberg         bufp += bytes_written;
4208edf8e2afSMika Westerberg         bytes_left -= bytes_written;
4209edf8e2afSMika Westerberg     } while (bytes_left > 0);
4210edf8e2afSMika Westerberg 
4211edf8e2afSMika Westerberg     return (0);
4212edf8e2afSMika Westerberg }
4213edf8e2afSMika Westerberg 
421441689bb3SRichard Henderson static int wmr_page_unprotect_regions(void *opaque, target_ulong start,
421541689bb3SRichard Henderson                                       target_ulong end, unsigned long flags)
421641689bb3SRichard Henderson {
421741689bb3SRichard Henderson     if ((flags & (PAGE_WRITE | PAGE_WRITE_ORG)) == PAGE_WRITE_ORG) {
42182c796d23SRichard Henderson         size_t step = MAX(TARGET_PAGE_SIZE, qemu_real_host_page_size());
421941689bb3SRichard Henderson 
422041689bb3SRichard Henderson         while (1) {
422141689bb3SRichard Henderson             page_unprotect(start, 0);
422241689bb3SRichard Henderson             if (end - start <= step) {
422341689bb3SRichard Henderson                 break;
422441689bb3SRichard Henderson             }
422541689bb3SRichard Henderson             start += step;
422641689bb3SRichard Henderson         }
422741689bb3SRichard Henderson     }
422841689bb3SRichard Henderson     return 0;
422941689bb3SRichard Henderson }
423041689bb3SRichard Henderson 
423150e33f52SRichard Henderson typedef struct {
423250e33f52SRichard Henderson     unsigned count;
423350e33f52SRichard Henderson     size_t size;
423450e33f52SRichard Henderson } CountAndSizeRegions;
423550e33f52SRichard Henderson 
423650e33f52SRichard Henderson static int wmr_count_and_size_regions(void *opaque, target_ulong start,
423750e33f52SRichard Henderson                                       target_ulong end, unsigned long flags)
423850e33f52SRichard Henderson {
423950e33f52SRichard Henderson     CountAndSizeRegions *css = opaque;
424050e33f52SRichard Henderson 
424150e33f52SRichard Henderson     css->count++;
424250e33f52SRichard Henderson     css->size += vma_dump_size(start, end, flags);
424350e33f52SRichard Henderson     return 0;
424450e33f52SRichard Henderson }
424550e33f52SRichard Henderson 
424650e33f52SRichard Henderson typedef struct {
424750e33f52SRichard Henderson     struct elf_phdr *phdr;
424850e33f52SRichard Henderson     off_t offset;
424950e33f52SRichard Henderson } FillRegionPhdr;
425050e33f52SRichard Henderson 
425150e33f52SRichard Henderson static int wmr_fill_region_phdr(void *opaque, target_ulong start,
425250e33f52SRichard Henderson                                 target_ulong end, unsigned long flags)
425350e33f52SRichard Henderson {
425450e33f52SRichard Henderson     FillRegionPhdr *d = opaque;
425550e33f52SRichard Henderson     struct elf_phdr *phdr = d->phdr;
425650e33f52SRichard Henderson 
425750e33f52SRichard Henderson     phdr->p_type = PT_LOAD;
425850e33f52SRichard Henderson     phdr->p_vaddr = start;
425950e33f52SRichard Henderson     phdr->p_paddr = 0;
426050e33f52SRichard Henderson     phdr->p_filesz = vma_dump_size(start, end, flags);
426150e33f52SRichard Henderson     phdr->p_offset = d->offset;
426250e33f52SRichard Henderson     d->offset += phdr->p_filesz;
426350e33f52SRichard Henderson     phdr->p_memsz = end - start;
426450e33f52SRichard Henderson     phdr->p_flags = (flags & PAGE_READ ? PF_R : 0)
426550e33f52SRichard Henderson                   | (flags & PAGE_WRITE_ORG ? PF_W : 0)
426650e33f52SRichard Henderson                   | (flags & PAGE_EXEC ? PF_X : 0);
426750e33f52SRichard Henderson     phdr->p_align = ELF_EXEC_PAGESIZE;
426850e33f52SRichard Henderson 
426950e33f52SRichard Henderson     bswap_phdr(phdr, 1);
427050e33f52SRichard Henderson     d->phdr = phdr + 1;
427150e33f52SRichard Henderson     return 0;
427250e33f52SRichard Henderson }
427350e33f52SRichard Henderson 
427450e33f52SRichard Henderson static int wmr_write_region(void *opaque, target_ulong start,
427550e33f52SRichard Henderson                             target_ulong end, unsigned long flags)
427650e33f52SRichard Henderson {
427750e33f52SRichard Henderson     int fd = *(int *)opaque;
427850e33f52SRichard Henderson     size_t size = vma_dump_size(start, end, flags);
427950e33f52SRichard Henderson 
428050e33f52SRichard Henderson     if (!size) {
428150e33f52SRichard Henderson         return 0;
428250e33f52SRichard Henderson     }
428350e33f52SRichard Henderson     return dump_write(fd, g2h_untagged(start), size);
428450e33f52SRichard Henderson }
428550e33f52SRichard Henderson 
4286edf8e2afSMika Westerberg /*
4287edf8e2afSMika Westerberg  * Write out ELF coredump.
4288edf8e2afSMika Westerberg  *
4289edf8e2afSMika Westerberg  * See documentation of ELF object file format in:
4290edf8e2afSMika Westerberg  * http://www.caldera.com/developers/devspecs/gabi41.pdf
4291edf8e2afSMika Westerberg  *
4292edf8e2afSMika Westerberg  * Coredump format in linux is following:
4293edf8e2afSMika Westerberg  *
4294edf8e2afSMika Westerberg  * 0   +----------------------+         \
4295edf8e2afSMika Westerberg  *     | ELF header           | ET_CORE  |
4296edf8e2afSMika Westerberg  *     +----------------------+          |
4297edf8e2afSMika Westerberg  *     | ELF program headers  |          |--- headers
4298edf8e2afSMika Westerberg  *     | - NOTE section       |          |
4299edf8e2afSMika Westerberg  *     | - PT_LOAD sections   |          |
4300edf8e2afSMika Westerberg  *     +----------------------+         /
4301edf8e2afSMika Westerberg  *     | NOTEs:               |
4302edf8e2afSMika Westerberg  *     | - NT_PRSTATUS        |
4303edf8e2afSMika Westerberg  *     | - NT_PRSINFO         |
4304edf8e2afSMika Westerberg  *     | - NT_AUXV            |
4305edf8e2afSMika Westerberg  *     +----------------------+ <-- aligned to target page
4306edf8e2afSMika Westerberg  *     | Process memory dump  |
4307edf8e2afSMika Westerberg  *     :                      :
4308edf8e2afSMika Westerberg  *     .                      .
4309edf8e2afSMika Westerberg  *     :                      :
4310edf8e2afSMika Westerberg  *     |                      |
4311edf8e2afSMika Westerberg  *     +----------------------+
4312edf8e2afSMika Westerberg  *
4313edf8e2afSMika Westerberg  * NT_PRSTATUS -> struct elf_prstatus (per thread)
4314edf8e2afSMika Westerberg  * NT_PRSINFO  -> struct elf_prpsinfo
4315edf8e2afSMika Westerberg  * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
4316edf8e2afSMika Westerberg  *
4317edf8e2afSMika Westerberg  * Format follows System V format as close as possible.  Current
4318edf8e2afSMika Westerberg  * version limitations are as follows:
4319edf8e2afSMika Westerberg  *     - no floating point registers are dumped
4320edf8e2afSMika Westerberg  *
4321edf8e2afSMika Westerberg  * Function returns 0 in case of success, negative errno otherwise.
4322edf8e2afSMika Westerberg  *
4323edf8e2afSMika Westerberg  * TODO: make this work also during runtime: it should be
4324edf8e2afSMika Westerberg  * possible to force coredump from running process and then
4325edf8e2afSMika Westerberg  * continue processing.  For example qemu could set up SIGUSR2
4326edf8e2afSMika Westerberg  * handler (provided that target process haven't registered
4327edf8e2afSMika Westerberg  * handler for that) that does the dump when signal is received.
4328edf8e2afSMika Westerberg  */
43299349b4f9SAndreas Färber static int elf_core_dump(int signr, const CPUArchState *env)
4330edf8e2afSMika Westerberg {
433129a0af61SRichard Henderson     const CPUState *cpu = env_cpu((CPUArchState *)env);
4332e4e5cb4aSIlya Leoshkevich     const TaskState *ts = (const TaskState *)get_task_state((CPUState *)cpu);
4333edf8e2afSMika Westerberg     struct rlimit dumpsize;
433450e33f52SRichard Henderson     CountAndSizeRegions css;
43352410d28dSRichard Henderson     off_t offset, note_offset, data_offset;
4336243c4706SRichard Henderson     size_t note_size;
433750e33f52SRichard Henderson     int cpus, ret;
4338edf8e2afSMika Westerberg     int fd = -1;
4339243c4706SRichard Henderson     CPUState *cpu_iter;
43400ea731dbSThomas Weißschuh 
43410ea731dbSThomas Weißschuh     if (prctl(PR_GET_DUMPABLE) == 0) {
43420ea731dbSThomas Weißschuh         return 0;
43430ea731dbSThomas Weißschuh     }
43440ea731dbSThomas Weißschuh 
4345f93b9953SRichard Henderson     if (getrlimit(RLIMIT_CORE, &dumpsize) < 0 || dumpsize.rlim_cur == 0) {
4346edf8e2afSMika Westerberg         return 0;
43473805d428SThomas Weißschuh     }
4348edf8e2afSMika Westerberg 
4349b5262077SRichard Henderson     cpu_list_lock();
4350b5262077SRichard Henderson     mmap_lock();
4351b5262077SRichard Henderson 
435241689bb3SRichard Henderson     /* By unprotecting, we merge vmas that might be split. */
435341689bb3SRichard Henderson     walk_memory_regions(NULL, wmr_page_unprotect_regions);
435441689bb3SRichard Henderson 
4355edf8e2afSMika Westerberg     /*
4356edf8e2afSMika Westerberg      * Walk through target process memory mappings and
43572410d28dSRichard Henderson      * set up structure containing this information.
4358edf8e2afSMika Westerberg      */
435950e33f52SRichard Henderson     memset(&css, 0, sizeof(css));
436050e33f52SRichard Henderson     walk_memory_regions(&css, wmr_count_and_size_regions);
43612410d28dSRichard Henderson 
43622410d28dSRichard Henderson     cpus = 0;
4363243c4706SRichard Henderson     CPU_FOREACH(cpu_iter) {
43642410d28dSRichard Henderson         cpus++;
43652410d28dSRichard Henderson     }
43662410d28dSRichard Henderson 
43672410d28dSRichard Henderson     offset = sizeof(struct elfhdr);
436850e33f52SRichard Henderson     offset += (css.count + 1) * sizeof(struct elf_phdr);
43692410d28dSRichard Henderson     note_offset = offset;
43702410d28dSRichard Henderson 
43712410d28dSRichard Henderson     offset += size_note("CORE", ts->info->auxv_len);
43722410d28dSRichard Henderson     offset += size_note("CORE", sizeof(struct target_elf_prpsinfo));
43732410d28dSRichard Henderson     offset += size_note("CORE", sizeof(struct target_elf_prstatus)) * cpus;
4374243c4706SRichard Henderson     note_size = offset - note_offset;
437550e33f52SRichard Henderson     data_offset = ROUND_UP(offset, ELF_EXEC_PAGESIZE);
43762410d28dSRichard Henderson 
43772410d28dSRichard Henderson     /* Do not dump if the corefile size exceeds the limit. */
437850e33f52SRichard Henderson     if (dumpsize.rlim_cur != RLIM_INFINITY
437950e33f52SRichard Henderson         && dumpsize.rlim_cur < data_offset + css.size) {
43802410d28dSRichard Henderson         errno = 0;
43812410d28dSRichard Henderson         goto out;
43822410d28dSRichard Henderson     }
4383edf8e2afSMika Westerberg 
4384106f8da6SRichard Henderson     {
4385106f8da6SRichard Henderson         g_autofree char *corefile = core_dump_filename(ts);
4386e0add9a8SRichard Henderson         fd = open(corefile, O_WRONLY | O_CREAT | O_TRUNC,
4387106f8da6SRichard Henderson                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
4388106f8da6SRichard Henderson     }
4389106f8da6SRichard Henderson     if (fd < 0) {
4390106f8da6SRichard Henderson         goto out;
4391106f8da6SRichard Henderson     }
4392106f8da6SRichard Henderson 
4393edf8e2afSMika Westerberg     /*
4394243c4706SRichard Henderson      * There is a fair amount of alignment padding within the notes
4395243c4706SRichard Henderson      * as well as preceeding the process memory.  Allocate a zeroed
4396243c4706SRichard Henderson      * block to hold it all.  Write all of the headers directly into
4397243c4706SRichard Henderson      * this buffer and then write it out as a block.
4398edf8e2afSMika Westerberg      */
4399243c4706SRichard Henderson     {
4400243c4706SRichard Henderson         g_autofree void *header = g_malloc0(data_offset);
440150e33f52SRichard Henderson         FillRegionPhdr frp;
4402243c4706SRichard Henderson         void *hptr, *dptr;
4403edf8e2afSMika Westerberg 
4404243c4706SRichard Henderson         /* Create elf file header. */
4405243c4706SRichard Henderson         hptr = header;
440650e33f52SRichard Henderson         fill_elf_header(hptr, css.count + 1, ELF_MACHINE, 0);
4407243c4706SRichard Henderson         hptr += sizeof(struct elfhdr);
4408edf8e2afSMika Westerberg 
4409243c4706SRichard Henderson         /* Create elf program headers. */
4410243c4706SRichard Henderson         fill_elf_note_phdr(hptr, note_size, note_offset);
4411243c4706SRichard Henderson         hptr += sizeof(struct elf_phdr);
4412edf8e2afSMika Westerberg 
441350e33f52SRichard Henderson         frp.phdr = hptr;
441450e33f52SRichard Henderson         frp.offset = data_offset;
441550e33f52SRichard Henderson         walk_memory_regions(&frp, wmr_fill_region_phdr);
441650e33f52SRichard Henderson         hptr = frp.phdr;
4417243c4706SRichard Henderson 
4418243c4706SRichard Henderson         /* Create the notes. */
4419243c4706SRichard Henderson         dptr = fill_note(&hptr, NT_AUXV, "CORE", ts->info->auxv_len);
4420243c4706SRichard Henderson         fill_auxv_note(dptr, ts);
4421243c4706SRichard Henderson 
4422243c4706SRichard Henderson         dptr = fill_note(&hptr, NT_PRPSINFO, "CORE",
4423243c4706SRichard Henderson                          sizeof(struct target_elf_prpsinfo));
4424243c4706SRichard Henderson         fill_prpsinfo_note(dptr, ts);
4425243c4706SRichard Henderson 
4426243c4706SRichard Henderson         CPU_FOREACH(cpu_iter) {
4427243c4706SRichard Henderson             dptr = fill_note(&hptr, NT_PRSTATUS, "CORE",
4428243c4706SRichard Henderson                              sizeof(struct target_elf_prstatus));
4429243c4706SRichard Henderson             fill_prstatus_note(dptr, ts, cpu_iter,
4430243c4706SRichard Henderson                                cpu_iter == cpu ? signr : 0);
4431243c4706SRichard Henderson         }
4432243c4706SRichard Henderson 
4433243c4706SRichard Henderson         if (dump_write(fd, header, data_offset) < 0) {
4434772034b6SPeter Maydell             goto out;
4435772034b6SPeter Maydell         }
4436edf8e2afSMika Westerberg     }
4437edf8e2afSMika Westerberg 
4438edf8e2afSMika Westerberg     /*
4439b4c7ab81SRichard Henderson      * Finally write process memory into the corefile as well.
4440edf8e2afSMika Westerberg      */
444150e33f52SRichard Henderson     if (walk_memory_regions(&fd, wmr_write_region) < 0) {
4442edf8e2afSMika Westerberg         goto out;
4443edf8e2afSMika Westerberg     }
4444ccb6f3eeSRichard Henderson     errno = 0;
4445edf8e2afSMika Westerberg 
4446edf8e2afSMika Westerberg  out:
4447ccb6f3eeSRichard Henderson     ret = -errno;
4448b5262077SRichard Henderson     mmap_unlock();
4449b5262077SRichard Henderson     cpu_list_unlock();
4450b35348c7SRichard Henderson     if (fd >= 0) {
4451ccb6f3eeSRichard Henderson         close(fd);
4452b35348c7SRichard Henderson     }
4453ccb6f3eeSRichard Henderson     return ret;
4454edf8e2afSMika Westerberg }
4455edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
4456edf8e2afSMika Westerberg 
4457e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
4458e5fe0c52Spbrook {
4459e5fe0c52Spbrook     init_thread(regs, infop);
4460e5fe0c52Spbrook }
4461