xref: /qemu/linux-user/elfload.c (revision f93b9953703be41408d5f0e09a871775d4be3c36)
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"
103b249d26SPeter Maydell #include "user-internals.h"
11db2af69dSRichard Henderson #include "signal-common.h"
123ad0a769SPeter Maydell #include "loader.h"
135423e6d3SPeter Maydell #include "user-mmap.h"
1476cad711SPaolo Bonzini #include "disas/disas.h"
15ce543844SPhilippe Mathieu-Daudé #include "qemu/bitops.h"
16f348b6d1SVeronia Bahaa #include "qemu/path.h"
17dc5e9ac7SMarkus Armbruster #include "qemu/queue.h"
18c6a2377fSRichard Henderson #include "qemu/guest-random.h"
196fd59449SRichard Henderson #include "qemu/units.h"
20ee947430SAlex Bennée #include "qemu/selfmap.h"
21370ed600SJamie Iles #include "qemu/lockable.h"
22c7f17e7bSRichard Henderson #include "qapi/error.h"
23cc37d98bSRichard Henderson #include "qemu/error-report.h"
24db2af69dSRichard Henderson #include "target_signal.h"
25327b75a4SIlya Leoshkevich #include "tcg/debuginfo.h"
2631e31b8aSbellard 
275a534314SPeter Maydell #ifdef TARGET_ARM
285a534314SPeter Maydell #include "target/arm/cpu-features.h"
295a534314SPeter Maydell #endif
305a534314SPeter Maydell 
31e58ffeb3Smalc #ifdef _ARCH_PPC64
32a6cc84f4Smalc #undef ARCH_DLINFO
33a6cc84f4Smalc #undef ELF_PLATFORM
34a6cc84f4Smalc #undef ELF_HWCAP
35ad6919dcSPeter Maydell #undef ELF_HWCAP2
36a6cc84f4Smalc #undef ELF_CLASS
37a6cc84f4Smalc #undef ELF_DATA
38a6cc84f4Smalc #undef ELF_ARCH
39a6cc84f4Smalc #endif
40a6cc84f4Smalc 
41c40f621aSRichard Henderson #ifndef TARGET_ARCH_HAS_SIGTRAMP_PAGE
42c40f621aSRichard Henderson #define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
43c40f621aSRichard Henderson #endif
44c40f621aSRichard Henderson 
45c40f621aSRichard Henderson typedef struct {
46c40f621aSRichard Henderson     const uint8_t *image;
47c40f621aSRichard Henderson     const uint32_t *relocs;
48c40f621aSRichard Henderson     unsigned image_size;
49c40f621aSRichard Henderson     unsigned reloc_count;
50c40f621aSRichard Henderson     unsigned sigreturn_ofs;
51c40f621aSRichard Henderson     unsigned rt_sigreturn_ofs;
52c40f621aSRichard Henderson } VdsoImageInfo;
53c40f621aSRichard Henderson 
54edf8e2afSMika Westerberg #define ELF_OSABI   ELFOSABI_SYSV
55edf8e2afSMika Westerberg 
56cb33da57Sblueswir1 /* from personality.h */
57cb33da57Sblueswir1 
58cb33da57Sblueswir1 /*
59cb33da57Sblueswir1  * Flags for bug emulation.
60cb33da57Sblueswir1  *
61cb33da57Sblueswir1  * These occupy the top three bytes.
62cb33da57Sblueswir1  */
63cb33da57Sblueswir1 enum {
64cb33da57Sblueswir1     ADDR_NO_RANDOMIZE = 0x0040000,      /* disable randomization of VA space */
65d97ef72eSRichard Henderson     FDPIC_FUNCPTRS =    0x0080000,      /* userspace function ptrs point to
66d97ef72eSRichard Henderson                                            descriptors (signal handling) */
67cb33da57Sblueswir1     MMAP_PAGE_ZERO =    0x0100000,
68cb33da57Sblueswir1     ADDR_COMPAT_LAYOUT = 0x0200000,
69cb33da57Sblueswir1     READ_IMPLIES_EXEC = 0x0400000,
70cb33da57Sblueswir1     ADDR_LIMIT_32BIT =  0x0800000,
71cb33da57Sblueswir1     SHORT_INODE =       0x1000000,
72cb33da57Sblueswir1     WHOLE_SECONDS =     0x2000000,
73cb33da57Sblueswir1     STICKY_TIMEOUTS =   0x4000000,
74cb33da57Sblueswir1     ADDR_LIMIT_3GB =    0x8000000,
75cb33da57Sblueswir1 };
76cb33da57Sblueswir1 
77cb33da57Sblueswir1 /*
78cb33da57Sblueswir1  * Personality types.
79cb33da57Sblueswir1  *
80cb33da57Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
81cb33da57Sblueswir1  * conflict with error returns.
82cb33da57Sblueswir1  */
83cb33da57Sblueswir1 enum {
84cb33da57Sblueswir1     PER_LINUX =         0x0000,
85cb33da57Sblueswir1     PER_LINUX_32BIT =   0x0000 | ADDR_LIMIT_32BIT,
86cb33da57Sblueswir1     PER_LINUX_FDPIC =   0x0000 | FDPIC_FUNCPTRS,
87cb33da57Sblueswir1     PER_SVR4 =          0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
88cb33da57Sblueswir1     PER_SVR3 =          0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
89d97ef72eSRichard Henderson     PER_SCOSVR3 =       0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE,
90cb33da57Sblueswir1     PER_OSR5 =          0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
91cb33da57Sblueswir1     PER_WYSEV386 =      0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
92cb33da57Sblueswir1     PER_ISCR4 =         0x0005 | STICKY_TIMEOUTS,
93cb33da57Sblueswir1     PER_BSD =           0x0006,
94cb33da57Sblueswir1     PER_SUNOS =         0x0006 | STICKY_TIMEOUTS,
95cb33da57Sblueswir1     PER_XENIX =         0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
96cb33da57Sblueswir1     PER_LINUX32 =       0x0008,
97cb33da57Sblueswir1     PER_LINUX32_3GB =   0x0008 | ADDR_LIMIT_3GB,
98cb33da57Sblueswir1     PER_IRIX32 =        0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
99cb33da57Sblueswir1     PER_IRIXN32 =       0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
100cb33da57Sblueswir1     PER_IRIX64 =        0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
101cb33da57Sblueswir1     PER_RISCOS =        0x000c,
102cb33da57Sblueswir1     PER_SOLARIS =       0x000d | STICKY_TIMEOUTS,
103cb33da57Sblueswir1     PER_UW7 =           0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
104cb33da57Sblueswir1     PER_OSF4 =          0x000f,                  /* OSF/1 v4 */
105cb33da57Sblueswir1     PER_HPUX =          0x0010,
106cb33da57Sblueswir1     PER_MASK =          0x00ff,
107cb33da57Sblueswir1 };
108cb33da57Sblueswir1 
109cb33da57Sblueswir1 /*
110cb33da57Sblueswir1  * Return the base personality without flags.
111cb33da57Sblueswir1  */
112cb33da57Sblueswir1 #define personality(pers)       (pers & PER_MASK)
113cb33da57Sblueswir1 
1143cb10cfaSChristophe Lyon int info_is_fdpic(struct image_info *info)
1153cb10cfaSChristophe Lyon {
1163cb10cfaSChristophe Lyon     return info->personality == PER_LINUX_FDPIC;
1173cb10cfaSChristophe Lyon }
1183cb10cfaSChristophe Lyon 
11983fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
12083fb7adfSbellard #ifndef MAP_DENYWRITE
12183fb7adfSbellard #define MAP_DENYWRITE 0
12283fb7adfSbellard #endif
12383fb7adfSbellard 
12483fb7adfSbellard /* should probably go in elf.h */
12583fb7adfSbellard #ifndef ELIBBAD
12683fb7adfSbellard #define ELIBBAD 80
12783fb7adfSbellard #endif
12883fb7adfSbellard 
129ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
13028490231SRichard Henderson #define ELF_DATA        ELFDATA2MSB
13128490231SRichard Henderson #else
13228490231SRichard Henderson #define ELF_DATA        ELFDATA2LSB
13328490231SRichard Henderson #endif
13428490231SRichard Henderson 
135a29f998dSPaolo Bonzini #ifdef TARGET_ABI_MIPSN32
136918fc54cSPaolo Bonzini typedef abi_ullong      target_elf_greg_t;
137918fc54cSPaolo Bonzini #define tswapreg(ptr)   tswap64(ptr)
138a29f998dSPaolo Bonzini #else
139a29f998dSPaolo Bonzini typedef abi_ulong       target_elf_greg_t;
140a29f998dSPaolo Bonzini #define tswapreg(ptr)   tswapal(ptr)
141a29f998dSPaolo Bonzini #endif
142a29f998dSPaolo Bonzini 
14321e807faSNathan Froyd #ifdef USE_UID16
1441ddd592fSPaolo Bonzini typedef abi_ushort      target_uid_t;
1451ddd592fSPaolo Bonzini typedef abi_ushort      target_gid_t;
14621e807faSNathan Froyd #else
147f8fd4fc4SPaolo Bonzini typedef abi_uint        target_uid_t;
148f8fd4fc4SPaolo Bonzini typedef abi_uint        target_gid_t;
14921e807faSNathan Froyd #endif
150f8fd4fc4SPaolo Bonzini typedef abi_int         target_pid_t;
15121e807faSNathan Froyd 
15230ac07d4Sbellard #ifdef TARGET_I386
15330ac07d4Sbellard 
15415338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
15515338fd7Sbellard 
15615338fd7Sbellard static uint32_t get_elf_hwcap(void)
15715338fd7Sbellard {
158a2247f8eSAndreas Färber     X86CPU *cpu = X86_CPU(thread_cpu);
159a2247f8eSAndreas Färber 
160a2247f8eSAndreas Färber     return cpu->env.features[FEAT_1_EDX];
16115338fd7Sbellard }
16215338fd7Sbellard 
16384409ddbSj_mayer #ifdef TARGET_X86_64
16484409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
16584409ddbSj_mayer #define ELF_ARCH       EM_X86_64
16684409ddbSj_mayer 
1679263ba84SRichard Henderson #define ELF_PLATFORM   "x86_64"
1689263ba84SRichard Henderson 
16984409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
17084409ddbSj_mayer {
17184409ddbSj_mayer     regs->rax = 0;
17284409ddbSj_mayer     regs->rsp = infop->start_stack;
17384409ddbSj_mayer     regs->rip = infop->entry;
17484409ddbSj_mayer }
17584409ddbSj_mayer 
1769edc5d79SMika Westerberg #define ELF_NREG    27
177c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
1789edc5d79SMika Westerberg 
1799edc5d79SMika Westerberg /*
1809edc5d79SMika Westerberg  * Note that ELF_NREG should be 29 as there should be place for
1819edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
1829edc5d79SMika Westerberg  * those.
1839edc5d79SMika Westerberg  *
1849edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
1859edc5d79SMika Westerberg  */
18605390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
1879edc5d79SMika Westerberg {
188030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[15]);
189030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[14]);
190030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[13]);
191030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[12]);
192030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EBP]);
193030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBX]);
194030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[11]);
195030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->regs[10]);
196030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->regs[9]);
197030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->regs[8]);
198030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->regs[R_EAX]);
199030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_ECX]);
200030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->regs[R_EDX]);
201030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->regs[R_ESI]);
202030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->regs[R_EDI]);
203030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_EAX]); /* XXX */
204030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->eip);
205030912e0SIlya Leoshkevich     (*regs)[17] = tswapreg(env->segs[R_CS].selector & 0xffff);
206030912e0SIlya Leoshkevich     (*regs)[18] = tswapreg(env->eflags);
207030912e0SIlya Leoshkevich     (*regs)[19] = tswapreg(env->regs[R_ESP]);
208030912e0SIlya Leoshkevich     (*regs)[20] = tswapreg(env->segs[R_SS].selector & 0xffff);
209030912e0SIlya Leoshkevich     (*regs)[21] = tswapreg(env->segs[R_FS].selector & 0xffff);
210030912e0SIlya Leoshkevich     (*regs)[22] = tswapreg(env->segs[R_GS].selector & 0xffff);
211030912e0SIlya Leoshkevich     (*regs)[23] = tswapreg(env->segs[R_DS].selector & 0xffff);
212030912e0SIlya Leoshkevich     (*regs)[24] = tswapreg(env->segs[R_ES].selector & 0xffff);
213030912e0SIlya Leoshkevich     (*regs)[25] = tswapreg(env->segs[R_FS].selector & 0xffff);
214030912e0SIlya Leoshkevich     (*regs)[26] = tswapreg(env->segs[R_GS].selector & 0xffff);
2159edc5d79SMika Westerberg }
2169edc5d79SMika Westerberg 
217d461b73eSRichard Henderson #if ULONG_MAX > UINT32_MAX
218d461b73eSRichard Henderson #define INIT_GUEST_COMMPAGE
219d461b73eSRichard Henderson static bool init_guest_commpage(void)
220d461b73eSRichard Henderson {
221d461b73eSRichard Henderson     /*
222d461b73eSRichard Henderson      * The vsyscall page is at a high negative address aka kernel space,
223d461b73eSRichard Henderson      * which means that we cannot actually allocate it with target_mmap.
224d461b73eSRichard Henderson      * We still should be able to use page_set_flags, unless the user
225d461b73eSRichard Henderson      * has specified -R reserved_va, which would trigger an assert().
226d461b73eSRichard Henderson      */
227d461b73eSRichard Henderson     if (reserved_va != 0 &&
22895059f9cSRichard Henderson         TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE - 1 > reserved_va) {
229d461b73eSRichard Henderson         error_report("Cannot allocate vsyscall page");
230d461b73eSRichard Henderson         exit(EXIT_FAILURE);
231d461b73eSRichard Henderson     }
232d461b73eSRichard Henderson     page_set_flags(TARGET_VSYSCALL_PAGE,
23349840a4aSRichard Henderson                    TARGET_VSYSCALL_PAGE | ~TARGET_PAGE_MASK,
234d461b73eSRichard Henderson                    PAGE_EXEC | PAGE_VALID);
235d461b73eSRichard Henderson     return true;
236d461b73eSRichard Henderson }
237d461b73eSRichard Henderson #endif
23884409ddbSj_mayer #else
23984409ddbSj_mayer 
24030ac07d4Sbellard /*
24130ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
24230ac07d4Sbellard  */
24330ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
24430ac07d4Sbellard 
24530ac07d4Sbellard /*
24630ac07d4Sbellard  * These are used to set parameters in the core dumps.
24730ac07d4Sbellard  */
24830ac07d4Sbellard #define ELF_CLASS       ELFCLASS32
24930ac07d4Sbellard #define ELF_ARCH        EM_386
25030ac07d4Sbellard 
2519263ba84SRichard Henderson #define ELF_PLATFORM get_elf_platform()
252872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
2539263ba84SRichard Henderson 
2549263ba84SRichard Henderson static const char *get_elf_platform(void)
2559263ba84SRichard Henderson {
2569263ba84SRichard Henderson     static char elf_platform[] = "i386";
2579263ba84SRichard Henderson     int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
2589263ba84SRichard Henderson     if (family > 6) {
2599263ba84SRichard Henderson         family = 6;
2609263ba84SRichard Henderson     }
2619263ba84SRichard Henderson     if (family >= 3) {
2629263ba84SRichard Henderson         elf_platform[1] = '0' + family;
2639263ba84SRichard Henderson     }
2649263ba84SRichard Henderson     return elf_platform;
2659263ba84SRichard Henderson }
2669263ba84SRichard Henderson 
267d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
268d97ef72eSRichard Henderson                                struct image_info *infop)
269e5fe0c52Spbrook {
270e5fe0c52Spbrook     regs->esp = infop->start_stack;
271e5fe0c52Spbrook     regs->eip = infop->entry;
272e5fe0c52Spbrook 
27330ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
27430ac07d4Sbellard        starts %edx contains a pointer to a function which might be
27530ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
27630ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
27730ac07d4Sbellard        that have been loaded before the code runs.
27830ac07d4Sbellard 
27930ac07d4Sbellard        A value of 0 tells we have no such handler.  */
280e5fe0c52Spbrook     regs->edx = 0;
281b346ff46Sbellard }
2829edc5d79SMika Westerberg 
2839edc5d79SMika Westerberg #define ELF_NREG    17
284c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
2859edc5d79SMika Westerberg 
2869edc5d79SMika Westerberg /*
2879edc5d79SMika Westerberg  * Note that ELF_NREG should be 19 as there should be place for
2889edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
2899edc5d79SMika Westerberg  * those.
2909edc5d79SMika Westerberg  *
2919edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
2929edc5d79SMika Westerberg  */
29305390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
2949edc5d79SMika Westerberg {
295030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[R_EBX]);
296030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[R_ECX]);
297030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[R_EDX]);
298030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[R_ESI]);
299030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EDI]);
300030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBP]);
301030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[R_EAX]);
302030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->segs[R_DS].selector & 0xffff);
303030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->segs[R_ES].selector & 0xffff);
304030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->segs[R_FS].selector & 0xffff);
305030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->segs[R_GS].selector & 0xffff);
306030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_EAX]); /* XXX */
307030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->eip);
308030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->segs[R_CS].selector & 0xffff);
309030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->eflags);
310030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_ESP]);
311030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->segs[R_SS].selector & 0xffff);
3129edc5d79SMika Westerberg }
313a1367443SRichard Henderson 
314a1367443SRichard Henderson /*
315a1367443SRichard Henderson  * i386 is the only target which supplies AT_SYSINFO for the vdso.
316a1367443SRichard Henderson  * All others only supply AT_SYSINFO_EHDR.
317a1367443SRichard Henderson  */
318a1367443SRichard Henderson #define DLINFO_ARCH_ITEMS (vdso_info != NULL)
319a1367443SRichard Henderson #define ARCH_DLINFO                                     \
320a1367443SRichard Henderson     do {                                                \
321a1367443SRichard Henderson         if (vdso_info) {                                \
322a1367443SRichard Henderson             NEW_AUX_ENT(AT_SYSINFO, vdso_info->entry);  \
323a1367443SRichard Henderson         }                                               \
324a1367443SRichard Henderson     } while (0)
325a1367443SRichard Henderson 
326a1367443SRichard Henderson #endif /* TARGET_X86_64 */
327b346ff46Sbellard 
3286b1a9d38SRichard Henderson #define VDSO_HEADER "vdso.c.inc"
329b346ff46Sbellard 
3309edc5d79SMika Westerberg #define USE_ELF_CORE_DUMP
331b346ff46Sbellard #define ELF_EXEC_PAGESIZE       4096
332b346ff46Sbellard 
333a1367443SRichard Henderson #endif /* TARGET_I386 */
334b346ff46Sbellard 
335b346ff46Sbellard #ifdef TARGET_ARM
336b346ff46Sbellard 
33724e76ff0SPeter Maydell #ifndef TARGET_AARCH64
33824e76ff0SPeter Maydell /* 32 bit ARM definitions */
33924e76ff0SPeter Maydell 
340b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_ARM
341b346ff46Sbellard #define ELF_CLASS       ELFCLASS32
342872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
343b346ff46Sbellard 
344d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
345d97ef72eSRichard Henderson                                struct image_info *infop)
346b346ff46Sbellard {
347992f48a0Sblueswir1     abi_long stack = infop->start_stack;
348b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
34999033caeSAlexander Graf 
350167e4cdcSPeter Maydell     regs->uregs[16] = ARM_CPU_MODE_USR;
351167e4cdcSPeter Maydell     if (infop->entry & 1) {
352167e4cdcSPeter Maydell         regs->uregs[16] |= CPSR_T;
353167e4cdcSPeter Maydell     }
354167e4cdcSPeter Maydell     regs->uregs[15] = infop->entry & 0xfffffffe;
355167e4cdcSPeter Maydell     regs->uregs[13] = infop->start_stack;
3562f619698Sbellard     /* FIXME - what to for failure of get_user()? */
357167e4cdcSPeter Maydell     get_user_ual(regs->uregs[2], stack + 8); /* envp */
358167e4cdcSPeter Maydell     get_user_ual(regs->uregs[1], stack + 4); /* envp */
359a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
360167e4cdcSPeter Maydell     regs->uregs[0] = 0;
361e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
362863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
363167e4cdcSPeter Maydell     regs->uregs[10] = infop->start_data;
3643cb10cfaSChristophe Lyon 
3653cb10cfaSChristophe Lyon     /* Support ARM FDPIC.  */
3663cb10cfaSChristophe Lyon     if (info_is_fdpic(infop)) {
3673cb10cfaSChristophe Lyon         /* As described in the ABI document, r7 points to the loadmap info
3683cb10cfaSChristophe Lyon          * prepared by the kernel. If an interpreter is needed, r8 points
3693cb10cfaSChristophe Lyon          * to the interpreter loadmap and r9 points to the interpreter
3703cb10cfaSChristophe Lyon          * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
3713cb10cfaSChristophe Lyon          * r9 points to the main program PT_DYNAMIC info.
3723cb10cfaSChristophe Lyon          */
3733cb10cfaSChristophe Lyon         regs->uregs[7] = infop->loadmap_addr;
3743cb10cfaSChristophe Lyon         if (infop->interpreter_loadmap_addr) {
3753cb10cfaSChristophe Lyon             /* Executable is dynamically loaded.  */
3763cb10cfaSChristophe Lyon             regs->uregs[8] = infop->interpreter_loadmap_addr;
3773cb10cfaSChristophe Lyon             regs->uregs[9] = infop->interpreter_pt_dynamic_addr;
3783cb10cfaSChristophe Lyon         } else {
3793cb10cfaSChristophe Lyon             regs->uregs[8] = 0;
3803cb10cfaSChristophe Lyon             regs->uregs[9] = infop->pt_dynamic_addr;
3813cb10cfaSChristophe Lyon         }
3823cb10cfaSChristophe Lyon     }
383b346ff46Sbellard }
384b346ff46Sbellard 
385edf8e2afSMika Westerberg #define ELF_NREG    18
386c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
387edf8e2afSMika Westerberg 
38805390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUARMState *env)
389edf8e2afSMika Westerberg {
39086cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->regs[0]);
39186cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->regs[1]);
39286cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->regs[2]);
39386cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->regs[3]);
39486cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->regs[4]);
39586cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->regs[5]);
39686cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->regs[6]);
39786cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->regs[7]);
39886cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->regs[8]);
39986cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->regs[9]);
40086cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->regs[10]);
40186cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->regs[11]);
40286cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->regs[12]);
40386cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->regs[13]);
40486cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->regs[14]);
40586cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->regs[15]);
406edf8e2afSMika Westerberg 
40786cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(cpsr_read((CPUARMState *)env));
40886cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->regs[0]); /* XXX */
409edf8e2afSMika Westerberg }
410edf8e2afSMika Westerberg 
41130ac07d4Sbellard #define USE_ELF_CORE_DUMP
41230ac07d4Sbellard #define ELF_EXEC_PAGESIZE       4096
41330ac07d4Sbellard 
414afce2927Sbellard enum
415afce2927Sbellard {
416afce2927Sbellard     ARM_HWCAP_ARM_SWP       = 1 << 0,
417afce2927Sbellard     ARM_HWCAP_ARM_HALF      = 1 << 1,
418afce2927Sbellard     ARM_HWCAP_ARM_THUMB     = 1 << 2,
419afce2927Sbellard     ARM_HWCAP_ARM_26BIT     = 1 << 3,
420afce2927Sbellard     ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
421afce2927Sbellard     ARM_HWCAP_ARM_FPA       = 1 << 5,
422afce2927Sbellard     ARM_HWCAP_ARM_VFP       = 1 << 6,
423afce2927Sbellard     ARM_HWCAP_ARM_EDSP      = 1 << 7,
424cf6de34aSRiku Voipio     ARM_HWCAP_ARM_JAVA      = 1 << 8,
425cf6de34aSRiku Voipio     ARM_HWCAP_ARM_IWMMXT    = 1 << 9,
42643ce393eSPeter Maydell     ARM_HWCAP_ARM_CRUNCH    = 1 << 10,
42743ce393eSPeter Maydell     ARM_HWCAP_ARM_THUMBEE   = 1 << 11,
42843ce393eSPeter Maydell     ARM_HWCAP_ARM_NEON      = 1 << 12,
42943ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3     = 1 << 13,
43043ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3D16  = 1 << 14,
43124682654SPeter Maydell     ARM_HWCAP_ARM_TLS       = 1 << 15,
43224682654SPeter Maydell     ARM_HWCAP_ARM_VFPv4     = 1 << 16,
43324682654SPeter Maydell     ARM_HWCAP_ARM_IDIVA     = 1 << 17,
43424682654SPeter Maydell     ARM_HWCAP_ARM_IDIVT     = 1 << 18,
43524682654SPeter Maydell     ARM_HWCAP_ARM_VFPD32    = 1 << 19,
43624682654SPeter Maydell     ARM_HWCAP_ARM_LPAE      = 1 << 20,
43724682654SPeter Maydell     ARM_HWCAP_ARM_EVTSTRM   = 1 << 21,
43823d7f14dSPeter Maydell     ARM_HWCAP_ARM_FPHP      = 1 << 22,
43923d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDHP   = 1 << 23,
44023d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDDP   = 1 << 24,
44123d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDFHM  = 1 << 25,
44223d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDBF16 = 1 << 26,
44323d7f14dSPeter Maydell     ARM_HWCAP_ARM_I8MM      = 1 << 27,
444afce2927Sbellard };
445afce2927Sbellard 
446ad6919dcSPeter Maydell enum {
447ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_AES      = 1 << 0,
448ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_PMULL    = 1 << 1,
449ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA1     = 1 << 2,
450ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA2     = 1 << 3,
451ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_CRC32    = 1 << 4,
45223d7f14dSPeter Maydell     ARM_HWCAP2_ARM_SB       = 1 << 5,
45323d7f14dSPeter Maydell     ARM_HWCAP2_ARM_SSBS     = 1 << 6,
454ad6919dcSPeter Maydell };
455ad6919dcSPeter Maydell 
4566b1275ffSPeter Maydell /* The commpage only exists for 32 bit kernels */
4576b1275ffSPeter Maydell 
45866346fafSRichard Henderson #define HI_COMMPAGE (intptr_t)0xffff0f00u
459ee947430SAlex Bennée 
460ee947430SAlex Bennée static bool init_guest_commpage(void)
46197cc7560SDr. David Alan Gilbert {
462d713cf4dSPhilippe Mathieu-Daudé     ARMCPU *cpu = ARM_CPU(thread_cpu);
463d713cf4dSPhilippe Mathieu-Daudé     abi_ptr commpage;
464d713cf4dSPhilippe Mathieu-Daudé     void *want;
465d713cf4dSPhilippe Mathieu-Daudé     void *addr;
466d713cf4dSPhilippe Mathieu-Daudé 
467d713cf4dSPhilippe Mathieu-Daudé     /*
468d713cf4dSPhilippe Mathieu-Daudé      * M-profile allocates maximum of 2GB address space, so can never
469d713cf4dSPhilippe Mathieu-Daudé      * allocate the commpage.  Skip it.
470d713cf4dSPhilippe Mathieu-Daudé      */
471d713cf4dSPhilippe Mathieu-Daudé     if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
472d713cf4dSPhilippe Mathieu-Daudé         return true;
473d713cf4dSPhilippe Mathieu-Daudé     }
474d713cf4dSPhilippe Mathieu-Daudé 
475d713cf4dSPhilippe Mathieu-Daudé     commpage = HI_COMMPAGE & -qemu_host_page_size;
476d713cf4dSPhilippe Mathieu-Daudé     want = g2h_untagged(commpage);
477d713cf4dSPhilippe Mathieu-Daudé     addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
4785c3e87f3SAlex Bennée                 MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
47997cc7560SDr. David Alan Gilbert 
4806cda41daSRichard Henderson     if (addr == MAP_FAILED) {
481ee947430SAlex Bennée         perror("Allocating guest commpage");
482ee947430SAlex Bennée         exit(EXIT_FAILURE);
483ee947430SAlex Bennée     }
484ee947430SAlex Bennée     if (addr != want) {
485ee947430SAlex Bennée         return false;
486806d1021SMeador Inge     }
487806d1021SMeador Inge 
488ee947430SAlex Bennée     /* Set kernel helper versions; rest of page is 0.  */
4896cda41daSRichard Henderson     __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu));
49097cc7560SDr. David Alan Gilbert 
4916cda41daSRichard Henderson     if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
49297cc7560SDr. David Alan Gilbert         perror("Protecting guest commpage");
493ee947430SAlex Bennée         exit(EXIT_FAILURE);
49497cc7560SDr. David Alan Gilbert     }
4956cda41daSRichard Henderson 
4966cda41daSRichard Henderson     page_set_flags(commpage, commpage | ~qemu_host_page_mask,
4976cda41daSRichard Henderson                    PAGE_READ | PAGE_EXEC | PAGE_VALID);
498ee947430SAlex Bennée     return true;
49997cc7560SDr. David Alan Gilbert }
500adf050b1SBenoit Canet 
501adf050b1SBenoit Canet #define ELF_HWCAP get_elf_hwcap()
502ad6919dcSPeter Maydell #define ELF_HWCAP2 get_elf_hwcap2()
503adf050b1SBenoit Canet 
504a55b9e72SHelge Deller uint32_t get_elf_hwcap(void)
505adf050b1SBenoit Canet {
506a2247f8eSAndreas Färber     ARMCPU *cpu = ARM_CPU(thread_cpu);
507adf050b1SBenoit Canet     uint32_t hwcaps = 0;
508adf050b1SBenoit Canet 
509adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_SWP;
510adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_HALF;
511adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_THUMB;
512adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
513adf050b1SBenoit Canet 
514adf050b1SBenoit Canet     /* probe for the extra features */
515adf050b1SBenoit Canet #define GET_FEATURE(feat, hwcap) \
516a2247f8eSAndreas Färber     do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
517962fcbf2SRichard Henderson 
518962fcbf2SRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
519962fcbf2SRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
520962fcbf2SRichard Henderson 
52124682654SPeter Maydell     /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
52224682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
523adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
524adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
525adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
52624682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
527bfa8a370SRichard Henderson     GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
528873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
529873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
530bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP);
531bfa8a370SRichard Henderson 
532bfa8a370SRichard Henderson     if (cpu_isar_feature(aa32_fpsp_v3, cpu) ||
533bfa8a370SRichard Henderson         cpu_isar_feature(aa32_fpdp_v3, cpu)) {
534bfa8a370SRichard Henderson         hwcaps |= ARM_HWCAP_ARM_VFPv3;
535bfa8a370SRichard Henderson         if (cpu_isar_feature(aa32_simd_r32, cpu)) {
536bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPD32;
537bfa8a370SRichard Henderson         } else {
538bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPv3D16;
539bfa8a370SRichard Henderson         }
540bfa8a370SRichard Henderson     }
541bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4);
542429b7e01SPeter Maydell     /*
543429b7e01SPeter Maydell      * MVFR1.FPHP and .SIMDHP must be in sync, and QEMU uses the same
544429b7e01SPeter Maydell      * isar_feature function for both. The kernel reports them as two hwcaps.
545429b7e01SPeter Maydell      */
546429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_FPHP);
547429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_ASIMDHP);
548429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_dp, ARM_HWCAP_ARM_ASIMDDP);
549429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fhm, ARM_HWCAP_ARM_ASIMDFHM);
550429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_bf16, ARM_HWCAP_ARM_ASIMDBF16);
551429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_i8mm, ARM_HWCAP_ARM_I8MM);
552adf050b1SBenoit Canet 
553adf050b1SBenoit Canet     return hwcaps;
554adf050b1SBenoit Canet }
555afce2927Sbellard 
55663c1b7deSPeter Maydell uint64_t get_elf_hwcap2(void)
557ad6919dcSPeter Maydell {
558ad6919dcSPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
55963c1b7deSPeter Maydell     uint64_t hwcaps = 0;
560ad6919dcSPeter Maydell 
561962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_aes, ARM_HWCAP2_ARM_AES);
562962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_pmull, ARM_HWCAP2_ARM_PMULL);
563962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha1, ARM_HWCAP2_ARM_SHA1);
564962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha2, ARM_HWCAP2_ARM_SHA2);
565962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_crc32, ARM_HWCAP2_ARM_CRC32);
566429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_sb, ARM_HWCAP2_ARM_SB);
567429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_ssbs, ARM_HWCAP2_ARM_SSBS);
568ad6919dcSPeter Maydell     return hwcaps;
569ad6919dcSPeter Maydell }
570ad6919dcSPeter Maydell 
571a55b9e72SHelge Deller const char *elf_hwcap_str(uint32_t bit)
572a55b9e72SHelge Deller {
573a55b9e72SHelge Deller     static const char *hwcap_str[] = {
574a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_SWP      )] = "swp",
575a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_HALF     )] = "half",
576a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_THUMB    )] = "thumb",
577a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_26BIT    )] = "26bit",
578a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_FAST_MULT)] = "fast_mult",
579a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_FPA      )] = "fpa",
580a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFP      )] = "vfp",
581a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_EDSP     )] = "edsp",
582a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_JAVA     )] = "java",
583a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IWMMXT   )] = "iwmmxt",
584a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_CRUNCH   )] = "crunch",
585a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_THUMBEE  )] = "thumbee",
586a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_NEON     )] = "neon",
587a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv3    )] = "vfpv3",
588a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv3D16 )] = "vfpv3d16",
589a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_TLS      )] = "tls",
590a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv4    )] = "vfpv4",
591a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IDIVA    )] = "idiva",
592a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IDIVT    )] = "idivt",
593a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPD32   )] = "vfpd32",
594a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_LPAE     )] = "lpae",
595a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_EVTSTRM  )] = "evtstrm",
59623d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_FPHP     )] = "fphp",
59723d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDHP  )] = "asimdhp",
59823d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDDP  )] = "asimddp",
59923d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDFHM )] = "asimdfhm",
60023d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDBF16)] = "asimdbf16",
60123d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_I8MM     )] = "i8mm",
602a55b9e72SHelge Deller     };
603a55b9e72SHelge Deller 
604a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
605a55b9e72SHelge Deller }
606a55b9e72SHelge Deller 
607a55b9e72SHelge Deller const char *elf_hwcap2_str(uint32_t bit)
608a55b9e72SHelge Deller {
609a55b9e72SHelge Deller     static const char *hwcap_str[] = {
610a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_AES  )] = "aes",
611a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_PMULL)] = "pmull",
612a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_SHA1 )] = "sha1",
613a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_SHA2 )] = "sha2",
614a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_CRC32)] = "crc32",
61523d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_ARM_SB   )] = "sb",
61623d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_ARM_SSBS )] = "ssbs",
617a55b9e72SHelge Deller     };
618a55b9e72SHelge Deller 
619a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
620a55b9e72SHelge Deller }
621a55b9e72SHelge Deller 
622ad6919dcSPeter Maydell #undef GET_FEATURE
623962fcbf2SRichard Henderson #undef GET_FEATURE_ID
624ad6919dcSPeter Maydell 
62513ec4ec3SRichard Henderson #define ELF_PLATFORM get_elf_platform()
62613ec4ec3SRichard Henderson 
62713ec4ec3SRichard Henderson static const char *get_elf_platform(void)
62813ec4ec3SRichard Henderson {
629b77af26eSRichard Henderson     CPUARMState *env = cpu_env(thread_cpu);
63013ec4ec3SRichard Henderson 
631ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
63213ec4ec3SRichard Henderson # define END  "b"
63313ec4ec3SRichard Henderson #else
63413ec4ec3SRichard Henderson # define END  "l"
63513ec4ec3SRichard Henderson #endif
63613ec4ec3SRichard Henderson 
63713ec4ec3SRichard Henderson     if (arm_feature(env, ARM_FEATURE_V8)) {
63813ec4ec3SRichard Henderson         return "v8" END;
63913ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V7)) {
64013ec4ec3SRichard Henderson         if (arm_feature(env, ARM_FEATURE_M)) {
64113ec4ec3SRichard Henderson             return "v7m" END;
64213ec4ec3SRichard Henderson         } else {
64313ec4ec3SRichard Henderson             return "v7" END;
64413ec4ec3SRichard Henderson         }
64513ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V6)) {
64613ec4ec3SRichard Henderson         return "v6" END;
64713ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V5)) {
64813ec4ec3SRichard Henderson         return "v5" END;
64913ec4ec3SRichard Henderson     } else {
65013ec4ec3SRichard Henderson         return "v4" END;
65113ec4ec3SRichard Henderson     }
65213ec4ec3SRichard Henderson 
65313ec4ec3SRichard Henderson #undef END
65413ec4ec3SRichard Henderson }
65513ec4ec3SRichard Henderson 
65624e76ff0SPeter Maydell #else
65724e76ff0SPeter Maydell /* 64 bit ARM definitions */
65824e76ff0SPeter Maydell 
659b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_AARCH64
66024e76ff0SPeter Maydell #define ELF_CLASS       ELFCLASS64
661ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
662e20e3ec9SRichard Henderson # define ELF_PLATFORM    "aarch64_be"
663e20e3ec9SRichard Henderson #else
66424e76ff0SPeter Maydell # define ELF_PLATFORM    "aarch64"
665e20e3ec9SRichard Henderson #endif
66624e76ff0SPeter Maydell 
66724e76ff0SPeter Maydell static inline void init_thread(struct target_pt_regs *regs,
66824e76ff0SPeter Maydell                                struct image_info *infop)
66924e76ff0SPeter Maydell {
67024e76ff0SPeter Maydell     abi_long stack = infop->start_stack;
67124e76ff0SPeter Maydell     memset(regs, 0, sizeof(*regs));
67224e76ff0SPeter Maydell 
67324e76ff0SPeter Maydell     regs->pc = infop->entry & ~0x3ULL;
67424e76ff0SPeter Maydell     regs->sp = stack;
67524e76ff0SPeter Maydell }
67624e76ff0SPeter Maydell 
67724e76ff0SPeter Maydell #define ELF_NREG    34
67824e76ff0SPeter Maydell typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
67924e76ff0SPeter Maydell 
68024e76ff0SPeter Maydell static void elf_core_copy_regs(target_elf_gregset_t *regs,
68124e76ff0SPeter Maydell                                const CPUARMState *env)
68224e76ff0SPeter Maydell {
68324e76ff0SPeter Maydell     int i;
68424e76ff0SPeter Maydell 
68524e76ff0SPeter Maydell     for (i = 0; i < 32; i++) {
68624e76ff0SPeter Maydell         (*regs)[i] = tswapreg(env->xregs[i]);
68724e76ff0SPeter Maydell     }
68824e76ff0SPeter Maydell     (*regs)[32] = tswapreg(env->pc);
68924e76ff0SPeter Maydell     (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env));
69024e76ff0SPeter Maydell }
69124e76ff0SPeter Maydell 
69224e76ff0SPeter Maydell #define USE_ELF_CORE_DUMP
69324e76ff0SPeter Maydell #define ELF_EXEC_PAGESIZE       4096
69424e76ff0SPeter Maydell 
69524e76ff0SPeter Maydell enum {
69624e76ff0SPeter Maydell     ARM_HWCAP_A64_FP            = 1 << 0,
69724e76ff0SPeter Maydell     ARM_HWCAP_A64_ASIMD         = 1 << 1,
69824e76ff0SPeter Maydell     ARM_HWCAP_A64_EVTSTRM       = 1 << 2,
69924e76ff0SPeter Maydell     ARM_HWCAP_A64_AES           = 1 << 3,
70024e76ff0SPeter Maydell     ARM_HWCAP_A64_PMULL         = 1 << 4,
70124e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA1          = 1 << 5,
70224e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA2          = 1 << 6,
70324e76ff0SPeter Maydell     ARM_HWCAP_A64_CRC32         = 1 << 7,
704955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ATOMICS       = 1 << 8,
705955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FPHP          = 1 << 9,
706955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDHP       = 1 << 10,
707955f56d4SArd Biesheuvel     ARM_HWCAP_A64_CPUID         = 1 << 11,
708955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDRDM      = 1 << 12,
709955f56d4SArd Biesheuvel     ARM_HWCAP_A64_JSCVT         = 1 << 13,
710955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FCMA          = 1 << 14,
711955f56d4SArd Biesheuvel     ARM_HWCAP_A64_LRCPC         = 1 << 15,
712955f56d4SArd Biesheuvel     ARM_HWCAP_A64_DCPOP         = 1 << 16,
713955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA3          = 1 << 17,
714955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM3           = 1 << 18,
715955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM4           = 1 << 19,
716955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDDP       = 1 << 20,
717955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA512        = 1 << 21,
718955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SVE           = 1 << 22,
7190083a1faSRichard Henderson     ARM_HWCAP_A64_ASIMDFHM      = 1 << 23,
7200083a1faSRichard Henderson     ARM_HWCAP_A64_DIT           = 1 << 24,
7210083a1faSRichard Henderson     ARM_HWCAP_A64_USCAT         = 1 << 25,
7220083a1faSRichard Henderson     ARM_HWCAP_A64_ILRCPC        = 1 << 26,
7230083a1faSRichard Henderson     ARM_HWCAP_A64_FLAGM         = 1 << 27,
7240083a1faSRichard Henderson     ARM_HWCAP_A64_SSBS          = 1 << 28,
7250083a1faSRichard Henderson     ARM_HWCAP_A64_SB            = 1 << 29,
7260083a1faSRichard Henderson     ARM_HWCAP_A64_PACA          = 1 << 30,
7270083a1faSRichard Henderson     ARM_HWCAP_A64_PACG          = 1UL << 31,
7282041df4aSRichard Henderson 
7292041df4aSRichard Henderson     ARM_HWCAP2_A64_DCPODP       = 1 << 0,
7302041df4aSRichard Henderson     ARM_HWCAP2_A64_SVE2         = 1 << 1,
7312041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEAES       = 1 << 2,
7322041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEPMULL     = 1 << 3,
7332041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEBITPERM   = 1 << 4,
7342041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESHA3      = 1 << 5,
7352041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESM4       = 1 << 6,
7362041df4aSRichard Henderson     ARM_HWCAP2_A64_FLAGM2       = 1 << 7,
7372041df4aSRichard Henderson     ARM_HWCAP2_A64_FRINT        = 1 << 8,
73868948d18SRichard Henderson     ARM_HWCAP2_A64_SVEI8MM      = 1 << 9,
73968948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF32MM     = 1 << 10,
74068948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF64MM     = 1 << 11,
74168948d18SRichard Henderson     ARM_HWCAP2_A64_SVEBF16      = 1 << 12,
74268948d18SRichard Henderson     ARM_HWCAP2_A64_I8MM         = 1 << 13,
74368948d18SRichard Henderson     ARM_HWCAP2_A64_BF16         = 1 << 14,
74468948d18SRichard Henderson     ARM_HWCAP2_A64_DGH          = 1 << 15,
74568948d18SRichard Henderson     ARM_HWCAP2_A64_RNG          = 1 << 16,
74668948d18SRichard Henderson     ARM_HWCAP2_A64_BTI          = 1 << 17,
74768948d18SRichard Henderson     ARM_HWCAP2_A64_MTE          = 1 << 18,
748f9982ceaSRichard Henderson     ARM_HWCAP2_A64_ECV          = 1 << 19,
749f9982ceaSRichard Henderson     ARM_HWCAP2_A64_AFP          = 1 << 20,
750f9982ceaSRichard Henderson     ARM_HWCAP2_A64_RPRES        = 1 << 21,
751f9982ceaSRichard Henderson     ARM_HWCAP2_A64_MTE3         = 1 << 22,
752f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME          = 1 << 23,
753f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I16I64   = 1 << 24,
754f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F64F64   = 1 << 25,
755f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I8I32    = 1 << 26,
756f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F16F32   = 1 << 27,
757f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_B16F32   = 1 << 28,
758f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F32F32   = 1 << 29,
759f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_FA64     = 1 << 30,
76023d7f14dSPeter Maydell     ARM_HWCAP2_A64_WFXT         = 1ULL << 31,
76123d7f14dSPeter Maydell     ARM_HWCAP2_A64_EBF16        = 1ULL << 32,
76223d7f14dSPeter Maydell     ARM_HWCAP2_A64_SVE_EBF16    = 1ULL << 33,
76323d7f14dSPeter Maydell     ARM_HWCAP2_A64_CSSC         = 1ULL << 34,
76423d7f14dSPeter Maydell     ARM_HWCAP2_A64_RPRFM        = 1ULL << 35,
76523d7f14dSPeter Maydell     ARM_HWCAP2_A64_SVE2P1       = 1ULL << 36,
76623d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME2         = 1ULL << 37,
76723d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME2P1       = 1ULL << 38,
76823d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_I16I32   = 1ULL << 39,
76923d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_BI32I32  = 1ULL << 40,
77023d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_B16B16   = 1ULL << 41,
77123d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_F16F16   = 1ULL << 42,
77223d7f14dSPeter Maydell     ARM_HWCAP2_A64_MOPS         = 1ULL << 43,
77323d7f14dSPeter Maydell     ARM_HWCAP2_A64_HBC          = 1ULL << 44,
77424e76ff0SPeter Maydell };
77524e76ff0SPeter Maydell 
77624e76ff0SPeter Maydell #define ELF_HWCAP   get_elf_hwcap()
7772041df4aSRichard Henderson #define ELF_HWCAP2  get_elf_hwcap2()
7782041df4aSRichard Henderson 
7792041df4aSRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
7802041df4aSRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
78124e76ff0SPeter Maydell 
782a55b9e72SHelge Deller uint32_t get_elf_hwcap(void)
78324e76ff0SPeter Maydell {
78424e76ff0SPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
78524e76ff0SPeter Maydell     uint32_t hwcaps = 0;
78624e76ff0SPeter Maydell 
78724e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_FP;
78824e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_ASIMD;
78937020ff1SAlex Bennée     hwcaps |= ARM_HWCAP_A64_CPUID;
79024e76ff0SPeter Maydell 
79124e76ff0SPeter Maydell     /* probe for the extra features */
792962fcbf2SRichard Henderson 
793962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES);
794962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL);
795962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha1, ARM_HWCAP_A64_SHA1);
796962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha256, ARM_HWCAP_A64_SHA2);
797962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha512, ARM_HWCAP_A64_SHA512);
798962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_crc32, ARM_HWCAP_A64_CRC32);
799962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha3, ARM_HWCAP_A64_SHA3);
800962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm3, ARM_HWCAP_A64_SM3);
801962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm4, ARM_HWCAP_A64_SM4);
8025763190fSRichard Henderson     GET_FEATURE_ID(aa64_fp16, ARM_HWCAP_A64_FPHP | ARM_HWCAP_A64_ASIMDHP);
803962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_atomics, ARM_HWCAP_A64_ATOMICS);
8045cfea248SMarielle Novastrider     GET_FEATURE_ID(aa64_lse2, ARM_HWCAP_A64_USCAT);
805962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_rdm, ARM_HWCAP_A64_ASIMDRDM);
806962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_dp, ARM_HWCAP_A64_ASIMDDP);
807962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA);
808cd208a1cSRichard Henderson     GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE);
80929d26ab2SRichard Henderson     GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG);
8101c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM);
8115cfea248SMarielle Novastrider     GET_FEATURE_ID(aa64_dit, ARM_HWCAP_A64_DIT);
8121c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
8139888bd1eSRichard Henderson     GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
814b89d9c98SRichard Henderson     GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
8150d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
8162677cf9fSPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
817a1229109SPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
818962fcbf2SRichard Henderson 
8192041df4aSRichard Henderson     return hwcaps;
8202041df4aSRichard Henderson }
8212041df4aSRichard Henderson 
82263c1b7deSPeter Maydell uint64_t get_elf_hwcap2(void)
8232041df4aSRichard Henderson {
8242041df4aSRichard Henderson     ARMCPU *cpu = ARM_CPU(thread_cpu);
82563c1b7deSPeter Maydell     uint64_t hwcaps = 0;
8262041df4aSRichard Henderson 
8270d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
828cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2, ARM_HWCAP2_A64_SVE2);
829cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_aes, ARM_HWCAP2_A64_SVEAES);
830cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_pmull128, ARM_HWCAP2_A64_SVEPMULL);
831cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_bitperm, ARM_HWCAP2_A64_SVEBITPERM);
832cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sha3, ARM_HWCAP2_A64_SVESHA3);
833cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sm4, ARM_HWCAP2_A64_SVESM4);
8342041df4aSRichard Henderson     GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
8352041df4aSRichard Henderson     GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
836cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_i8mm, ARM_HWCAP2_A64_SVEI8MM);
837cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f32mm, ARM_HWCAP2_A64_SVEF32MM);
838cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f64mm, ARM_HWCAP2_A64_SVEF64MM);
8396c47a905SRichard Henderson     GET_FEATURE_ID(aa64_sve_bf16, ARM_HWCAP2_A64_SVEBF16);
840cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_i8mm, ARM_HWCAP2_A64_I8MM);
8416c47a905SRichard Henderson     GET_FEATURE_ID(aa64_bf16, ARM_HWCAP2_A64_BF16);
84268948d18SRichard Henderson     GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG);
84368948d18SRichard Henderson     GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI);
84468948d18SRichard Henderson     GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE);
8455cfea248SMarielle Novastrider     GET_FEATURE_ID(aa64_mte3, ARM_HWCAP2_A64_MTE3);
846f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme, (ARM_HWCAP2_A64_SME |
847f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F32F32 |
848f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_B16F32 |
849f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F16F32 |
850f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_I8I32));
851f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_f64f64, ARM_HWCAP2_A64_SME_F64F64);
852f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_i16i64, ARM_HWCAP2_A64_SME_I16I64);
853f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_fa64, ARM_HWCAP2_A64_SME_FA64);
8543039b090SPeter Maydell     GET_FEATURE_ID(aa64_hbc, ARM_HWCAP2_A64_HBC);
855706a92fbSPeter Maydell     GET_FEATURE_ID(aa64_mops, ARM_HWCAP2_A64_MOPS);
85624e76ff0SPeter Maydell 
85724e76ff0SPeter Maydell     return hwcaps;
85824e76ff0SPeter Maydell }
85924e76ff0SPeter Maydell 
860a55b9e72SHelge Deller const char *elf_hwcap_str(uint32_t bit)
861a55b9e72SHelge Deller {
862a55b9e72SHelge Deller     static const char *hwcap_str[] = {
863a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FP      )] = "fp",
864a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMD   )] = "asimd",
865a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_EVTSTRM )] = "evtstrm",
866a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_AES     )] = "aes",
867a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PMULL   )] = "pmull",
868a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA1    )] = "sha1",
869a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA2    )] = "sha2",
870a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_CRC32   )] = "crc32",
871a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ATOMICS )] = "atomics",
872a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FPHP    )] = "fphp",
873a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDHP )] = "asimdhp",
874a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_CPUID   )] = "cpuid",
875a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDRDM)] = "asimdrdm",
876a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_JSCVT   )] = "jscvt",
877a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FCMA    )] = "fcma",
878a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_LRCPC   )] = "lrcpc",
879a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_DCPOP   )] = "dcpop",
880a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA3    )] = "sha3",
881a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SM3     )] = "sm3",
882a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SM4     )] = "sm4",
883a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDDP )] = "asimddp",
884a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA512  )] = "sha512",
885a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SVE     )] = "sve",
886a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDFHM)] = "asimdfhm",
887a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_DIT     )] = "dit",
888a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_USCAT   )] = "uscat",
889a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ILRCPC  )] = "ilrcpc",
890a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FLAGM   )] = "flagm",
891a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SSBS    )] = "ssbs",
892a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SB      )] = "sb",
893a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PACA    )] = "paca",
894a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PACG    )] = "pacg",
895a55b9e72SHelge Deller     };
896a55b9e72SHelge Deller 
897a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
898a55b9e72SHelge Deller }
899a55b9e72SHelge Deller 
900a55b9e72SHelge Deller const char *elf_hwcap2_str(uint32_t bit)
901a55b9e72SHelge Deller {
902a55b9e72SHelge Deller     static const char *hwcap_str[] = {
903a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_DCPODP       )] = "dcpodp",
904a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVE2         )] = "sve2",
905a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEAES       )] = "sveaes",
906a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEPMULL     )] = "svepmull",
907a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEBITPERM   )] = "svebitperm",
908a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVESHA3      )] = "svesha3",
909a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVESM4       )] = "svesm4",
910a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_FLAGM2       )] = "flagm2",
911a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_FRINT        )] = "frint",
912a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEI8MM      )] = "svei8mm",
913a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEF32MM     )] = "svef32mm",
914a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEF64MM     )] = "svef64mm",
915a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEBF16      )] = "svebf16",
916a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_I8MM         )] = "i8mm",
917a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_BF16         )] = "bf16",
918a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_DGH          )] = "dgh",
919a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_RNG          )] = "rng",
920a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_BTI          )] = "bti",
921a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_MTE          )] = "mte",
922a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_ECV          )] = "ecv",
923a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_AFP          )] = "afp",
924a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_RPRES        )] = "rpres",
925a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_MTE3         )] = "mte3",
926a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SME          )] = "sme",
927e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_I16I64   )] = "smei16i64",
928e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F64F64   )] = "smef64f64",
929e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_I8I32    )] = "smei8i32",
930e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F16F32   )] = "smef16f32",
931e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_B16F32   )] = "smeb16f32",
932e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F32F32   )] = "smef32f32",
933e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_FA64     )] = "smefa64",
93423d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_WFXT         )] = "wfxt",
93523d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_EBF16      )] = "ebf16",
93623d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SVE_EBF16  )] = "sveebf16",
93723d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_CSSC       )] = "cssc",
93823d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_RPRFM      )] = "rprfm",
93923d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SVE2P1     )] = "sve2p1",
94023d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME2       )] = "sme2",
94123d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME2P1     )] = "sme2p1",
94223d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_I16I32 )] = "smei16i32",
94323d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_BI32I32)] = "smebi32i32",
94423d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_B16B16 )] = "smeb16b16",
94523d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_F16F16 )] = "smef16f16",
94623d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_MOPS       )] = "mops",
94723d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_HBC        )] = "hbc",
948a55b9e72SHelge Deller     };
949a55b9e72SHelge Deller 
950a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
951a55b9e72SHelge Deller }
952a55b9e72SHelge Deller 
9532041df4aSRichard Henderson #undef GET_FEATURE_ID
9542041df4aSRichard Henderson 
95524e76ff0SPeter Maydell #endif /* not TARGET_AARCH64 */
956a9f495b9SRichard Henderson 
957ee95fae0SRichard Henderson #if TARGET_BIG_ENDIAN
958ee95fae0SRichard Henderson # define VDSO_HEADER  "vdso-be.c.inc"
959ee95fae0SRichard Henderson #else
960ee95fae0SRichard Henderson # define VDSO_HEADER  "vdso-le.c.inc"
961ee95fae0SRichard Henderson #endif
962ee95fae0SRichard Henderson 
96324e76ff0SPeter Maydell #endif /* TARGET_ARM */
96430ac07d4Sbellard 
965853d6f7aSbellard #ifdef TARGET_SPARC
966a315a145Sbellard #ifdef TARGET_SPARC64
967853d6f7aSbellard 
968cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
969cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV | HWCAP_SPARC_V9)
970992f48a0Sblueswir1 #ifndef TARGET_ABI32
971cb33da57Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
972992f48a0Sblueswir1 #else
973992f48a0Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
974992f48a0Sblueswir1 #endif
975853d6f7aSbellard 
976a315a145Sbellard #define ELF_CLASS   ELFCLASS64
9775ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
978a315a145Sbellard #else
979cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
980cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV)
981853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
982853d6f7aSbellard #define ELF_ARCH    EM_SPARC
983089a2256SRichard Henderson #endif /* TARGET_SPARC64 */
984853d6f7aSbellard 
985d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
986d97ef72eSRichard Henderson                                struct image_info *infop)
987853d6f7aSbellard {
988089a2256SRichard Henderson     /* Note that target_cpu_copy_regs does not read psr/tstate. */
989f5155289Sbellard     regs->pc = infop->entry;
990f5155289Sbellard     regs->npc = regs->pc + 4;
991f5155289Sbellard     regs->y = 0;
992089a2256SRichard Henderson     regs->u_regs[14] = (infop->start_stack - 16 * sizeof(abi_ulong)
993089a2256SRichard Henderson                         - TARGET_STACK_BIAS);
994853d6f7aSbellard }
995089a2256SRichard Henderson #endif /* TARGET_SPARC */
996853d6f7aSbellard 
99767867308Sbellard #ifdef TARGET_PPC
99867867308Sbellard 
9994ecd4d16SPeter Crosthwaite #define ELF_MACHINE    PPC_ELF_MACHINE
100067867308Sbellard 
100174154d7eSThomas Huth #if defined(TARGET_PPC64)
100284409ddbSj_mayer 
100384409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
100484409ddbSj_mayer 
100584409ddbSj_mayer #define ELF_CLASS       ELFCLASS64
100684409ddbSj_mayer 
100784409ddbSj_mayer #else
100884409ddbSj_mayer 
100967867308Sbellard #define ELF_CLASS       ELFCLASS32
1010872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
101184409ddbSj_mayer 
101284409ddbSj_mayer #endif
101384409ddbSj_mayer 
101467867308Sbellard #define ELF_ARCH        EM_PPC
101567867308Sbellard 
1016df84e4f3SNathan Froyd /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
1017df84e4f3SNathan Froyd    See arch/powerpc/include/asm/cputable.h.  */
1018df84e4f3SNathan Froyd enum {
10193efa9a67Smalc     QEMU_PPC_FEATURE_32 = 0x80000000,
10203efa9a67Smalc     QEMU_PPC_FEATURE_64 = 0x40000000,
10213efa9a67Smalc     QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
10223efa9a67Smalc     QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
10233efa9a67Smalc     QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
10243efa9a67Smalc     QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
10253efa9a67Smalc     QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
10263efa9a67Smalc     QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
10273efa9a67Smalc     QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
10283efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
10293efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
10303efa9a67Smalc     QEMU_PPC_FEATURE_NO_TB = 0x00100000,
10313efa9a67Smalc     QEMU_PPC_FEATURE_POWER4 = 0x00080000,
10323efa9a67Smalc     QEMU_PPC_FEATURE_POWER5 = 0x00040000,
10333efa9a67Smalc     QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
10343efa9a67Smalc     QEMU_PPC_FEATURE_CELL = 0x00010000,
10353efa9a67Smalc     QEMU_PPC_FEATURE_BOOKE = 0x00008000,
10363efa9a67Smalc     QEMU_PPC_FEATURE_SMT = 0x00004000,
10373efa9a67Smalc     QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
10383efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
10393efa9a67Smalc     QEMU_PPC_FEATURE_PA6T = 0x00000800,
10403efa9a67Smalc     QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
10413efa9a67Smalc     QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
10423efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
10433efa9a67Smalc     QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
10443efa9a67Smalc     QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
1045df84e4f3SNathan Froyd 
10463efa9a67Smalc     QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
10473efa9a67Smalc     QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
1048a60438ddSTom Musta 
1049a60438ddSTom Musta     /* Feature definitions in AT_HWCAP2.  */
1050a60438ddSTom Musta     QEMU_PPC_FEATURE2_ARCH_2_07 = 0x80000000, /* ISA 2.07 */
1051a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_HTM = 0x40000000, /* Hardware Transactional Memory */
1052a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_DSCR = 0x20000000, /* Data Stream Control Register */
1053a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */
1054a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */
1055a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */
105624c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_VEC_CRYPTO = 0x02000000,
105724c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NOSC = 0x01000000,
1058be0c46d4SSandipan Das     QEMU_PPC_FEATURE2_ARCH_3_00 = 0x00800000, /* ISA 3.00 */
105924c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HAS_IEEE128 = 0x00400000, /* VSX IEEE Bin Float 128-bit */
106024c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */
106124c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */
106224c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */
106396c343ccSJoel Stanley     QEMU_PPC_FEATURE2_ARCH_3_1 = 0x00040000, /* ISA 3.1 */
106496c343ccSJoel Stanley     QEMU_PPC_FEATURE2_MMA = 0x00020000, /* Matrix-Multiply Assist */
1065df84e4f3SNathan Froyd };
1066df84e4f3SNathan Froyd 
1067df84e4f3SNathan Froyd #define ELF_HWCAP get_elf_hwcap()
1068df84e4f3SNathan Froyd 
1069df84e4f3SNathan Froyd static uint32_t get_elf_hwcap(void)
1070df84e4f3SNathan Froyd {
1071a2247f8eSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
1072df84e4f3SNathan Froyd     uint32_t features = 0;
1073df84e4f3SNathan Froyd 
1074df84e4f3SNathan Froyd     /* We don't have to be terribly complete here; the high points are
1075df84e4f3SNathan Froyd        Altivec/FP/SPE support.  Anything else is just a bonus.  */
1076df84e4f3SNathan Froyd #define GET_FEATURE(flag, feature)                                      \
1077a2247f8eSAndreas Färber     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
107858eb5308SMichael Walle #define GET_FEATURE2(flags, feature) \
107958eb5308SMichael Walle     do { \
108058eb5308SMichael Walle         if ((cpu->env.insns_flags2 & flags) == flags) { \
108158eb5308SMichael Walle             features |= feature; \
108258eb5308SMichael Walle         } \
108358eb5308SMichael Walle     } while (0)
10843efa9a67Smalc     GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
10853efa9a67Smalc     GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
10863efa9a67Smalc     GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
10873efa9a67Smalc     GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
10883efa9a67Smalc     GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
10893efa9a67Smalc     GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
10903efa9a67Smalc     GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
10913efa9a67Smalc     GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
10920e019746STom Musta     GET_FEATURE2(PPC2_DFP, QEMU_PPC_FEATURE_HAS_DFP);
10930e019746STom Musta     GET_FEATURE2(PPC2_VSX, QEMU_PPC_FEATURE_HAS_VSX);
10940e019746STom Musta     GET_FEATURE2((PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 |
10950e019746STom Musta                   PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206),
10960e019746STom Musta                   QEMU_PPC_FEATURE_ARCH_2_06);
1097df84e4f3SNathan Froyd #undef GET_FEATURE
10980e019746STom Musta #undef GET_FEATURE2
1099df84e4f3SNathan Froyd 
1100df84e4f3SNathan Froyd     return features;
1101df84e4f3SNathan Froyd }
1102df84e4f3SNathan Froyd 
1103a60438ddSTom Musta #define ELF_HWCAP2 get_elf_hwcap2()
1104a60438ddSTom Musta 
1105a60438ddSTom Musta static uint32_t get_elf_hwcap2(void)
1106a60438ddSTom Musta {
1107a60438ddSTom Musta     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
1108a60438ddSTom Musta     uint32_t features = 0;
1109a60438ddSTom Musta 
1110a60438ddSTom Musta #define GET_FEATURE(flag, feature)                                      \
1111a60438ddSTom Musta     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
1112a60438ddSTom Musta #define GET_FEATURE2(flag, feature)                                      \
1113a60438ddSTom Musta     do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
1114a60438ddSTom Musta 
1115a60438ddSTom Musta     GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL);
1116a60438ddSTom Musta     GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR);
1117a60438ddSTom Musta     GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
111824c373ecSLaurent Vivier                   PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07 |
111924c373ecSLaurent Vivier                   QEMU_PPC_FEATURE2_VEC_CRYPTO);
112024c373ecSLaurent Vivier     GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 |
11218a589aebSKhem Raj                  QEMU_PPC_FEATURE2_DARN | QEMU_PPC_FEATURE2_HAS_IEEE128);
112296c343ccSJoel Stanley     GET_FEATURE2(PPC2_ISA310, QEMU_PPC_FEATURE2_ARCH_3_1 |
112396c343ccSJoel Stanley                  QEMU_PPC_FEATURE2_MMA);
1124a60438ddSTom Musta 
1125a60438ddSTom Musta #undef GET_FEATURE
1126a60438ddSTom Musta #undef GET_FEATURE2
1127a60438ddSTom Musta 
1128a60438ddSTom Musta     return features;
1129a60438ddSTom Musta }
1130a60438ddSTom Musta 
1131f5155289Sbellard /*
1132f5155289Sbellard  * The requirements here are:
1133f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
1134f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
1135f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
1136f5155289Sbellard  *   AT_IGNOREPPC is used for that.
1137f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
1138f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
1139f5155289Sbellard  */
11400bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
1141f5155289Sbellard #define ARCH_DLINFO                                     \
1142f5155289Sbellard     do {                                                \
1143623e250aSTom Musta         PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);              \
1144f5155289Sbellard         /*                                              \
114582991bedSPeter Maydell          * Handle glibc compatibility: these magic entries must \
114682991bedSPeter Maydell          * be at the lowest addresses in the final auxv.        \
1147f5155289Sbellard          */                                             \
11480bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
11490bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
115082991bedSPeter Maydell         NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
115182991bedSPeter Maydell         NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
115282991bedSPeter Maydell         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                 \
1153f5155289Sbellard     } while (0)
1154f5155289Sbellard 
115567867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
115667867308Sbellard {
115767867308Sbellard     _regs->gpr[1] = infop->start_stack;
115874154d7eSThomas Huth #if defined(TARGET_PPC64)
1159d90b94cdSDoug Kwan     if (get_ppc64_abi(infop) < 2) {
11602ccf97ecSPeter Maydell         uint64_t val;
11612ccf97ecSPeter Maydell         get_user_u64(val, infop->entry + 8);
11622ccf97ecSPeter Maydell         _regs->gpr[2] = val + infop->load_bias;
11632ccf97ecSPeter Maydell         get_user_u64(val, infop->entry);
11642ccf97ecSPeter Maydell         infop->entry = val + infop->load_bias;
1165d90b94cdSDoug Kwan     } else {
1166d90b94cdSDoug Kwan         _regs->gpr[12] = infop->entry;  /* r12 set to global entry address */
1167d90b94cdSDoug Kwan     }
116884409ddbSj_mayer #endif
116967867308Sbellard     _regs->nip = infop->entry;
117067867308Sbellard }
117167867308Sbellard 
1172e2f3e741SNathan Froyd /* See linux kernel: arch/powerpc/include/asm/elf.h.  */
1173e2f3e741SNathan Froyd #define ELF_NREG 48
1174e2f3e741SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1175e2f3e741SNathan Froyd 
117605390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *env)
1177e2f3e741SNathan Froyd {
1178e2f3e741SNathan Froyd     int i;
1179e2f3e741SNathan Froyd     target_ulong ccr = 0;
1180e2f3e741SNathan Froyd 
1181e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
118286cd7b2dSPaolo Bonzini         (*regs)[i] = tswapreg(env->gpr[i]);
1183e2f3e741SNathan Froyd     }
1184e2f3e741SNathan Froyd 
118586cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->nip);
118686cd7b2dSPaolo Bonzini     (*regs)[33] = tswapreg(env->msr);
118786cd7b2dSPaolo Bonzini     (*regs)[35] = tswapreg(env->ctr);
118886cd7b2dSPaolo Bonzini     (*regs)[36] = tswapreg(env->lr);
118910de0521SMatheus Ferst     (*regs)[37] = tswapreg(cpu_read_xer(env));
1190e2f3e741SNathan Froyd 
11912060436aSHarsh Prateek Bora     ccr = ppc_get_cr(env);
119286cd7b2dSPaolo Bonzini     (*regs)[38] = tswapreg(ccr);
1193e2f3e741SNathan Froyd }
1194e2f3e741SNathan Froyd 
1195e2f3e741SNathan Froyd #define USE_ELF_CORE_DUMP
119667867308Sbellard #define ELF_EXEC_PAGESIZE       4096
119767867308Sbellard 
1198e34136d9SRichard Henderson #ifndef TARGET_PPC64
1199e34136d9SRichard Henderson # define VDSO_HEADER  "vdso-32.c.inc"
1200e34136d9SRichard Henderson #elif TARGET_BIG_ENDIAN
1201e34136d9SRichard Henderson # define VDSO_HEADER  "vdso-64.c.inc"
1202e34136d9SRichard Henderson #else
1203e34136d9SRichard Henderson # define VDSO_HEADER  "vdso-64le.c.inc"
1204e34136d9SRichard Henderson #endif
1205e34136d9SRichard Henderson 
120667867308Sbellard #endif
120767867308Sbellard 
12083418fe25SSong Gao #ifdef TARGET_LOONGARCH64
12093418fe25SSong Gao 
12103418fe25SSong Gao #define ELF_CLASS   ELFCLASS64
12113418fe25SSong Gao #define ELF_ARCH    EM_LOONGARCH
1212872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
12133418fe25SSong Gao 
12143418fe25SSong Gao #define elf_check_arch(x) ((x) == EM_LOONGARCH)
12153418fe25SSong Gao 
121600cc2934SRichard Henderson #define VDSO_HEADER "vdso.c.inc"
121700cc2934SRichard Henderson 
12183418fe25SSong Gao static inline void init_thread(struct target_pt_regs *regs,
12193418fe25SSong Gao                                struct image_info *infop)
12203418fe25SSong Gao {
12213418fe25SSong Gao     /*Set crmd PG,DA = 1,0 */
12223418fe25SSong Gao     regs->csr.crmd = 2 << 3;
12233418fe25SSong Gao     regs->csr.era = infop->entry;
12243418fe25SSong Gao     regs->regs[3] = infop->start_stack;
12253418fe25SSong Gao }
12263418fe25SSong Gao 
12273418fe25SSong Gao /* See linux kernel: arch/loongarch/include/asm/elf.h */
12283418fe25SSong Gao #define ELF_NREG 45
12293418fe25SSong Gao typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
12303418fe25SSong Gao 
12313418fe25SSong Gao enum {
12323418fe25SSong Gao     TARGET_EF_R0 = 0,
12333418fe25SSong Gao     TARGET_EF_CSR_ERA = TARGET_EF_R0 + 33,
12343418fe25SSong Gao     TARGET_EF_CSR_BADV = TARGET_EF_R0 + 34,
12353418fe25SSong Gao };
12363418fe25SSong Gao 
12373418fe25SSong Gao static void elf_core_copy_regs(target_elf_gregset_t *regs,
12383418fe25SSong Gao                                const CPULoongArchState *env)
12393418fe25SSong Gao {
12403418fe25SSong Gao     int i;
12413418fe25SSong Gao 
12423418fe25SSong Gao     (*regs)[TARGET_EF_R0] = 0;
12433418fe25SSong Gao 
12443418fe25SSong Gao     for (i = 1; i < ARRAY_SIZE(env->gpr); i++) {
12453418fe25SSong Gao         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->gpr[i]);
12463418fe25SSong Gao     }
12473418fe25SSong Gao 
12483418fe25SSong Gao     (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->pc);
12493418fe25SSong Gao     (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV);
12503418fe25SSong Gao }
12513418fe25SSong Gao 
12523418fe25SSong Gao #define USE_ELF_CORE_DUMP
12533418fe25SSong Gao #define ELF_EXEC_PAGESIZE        4096
12543418fe25SSong Gao 
12553418fe25SSong Gao #define ELF_HWCAP get_elf_hwcap()
12563418fe25SSong Gao 
12573418fe25SSong Gao /* See arch/loongarch/include/uapi/asm/hwcap.h */
12583418fe25SSong Gao enum {
12593418fe25SSong Gao     HWCAP_LOONGARCH_CPUCFG   = (1 << 0),
12603418fe25SSong Gao     HWCAP_LOONGARCH_LAM      = (1 << 1),
12613418fe25SSong Gao     HWCAP_LOONGARCH_UAL      = (1 << 2),
12623418fe25SSong Gao     HWCAP_LOONGARCH_FPU      = (1 << 3),
12633418fe25SSong Gao     HWCAP_LOONGARCH_LSX      = (1 << 4),
12643418fe25SSong Gao     HWCAP_LOONGARCH_LASX     = (1 << 5),
12653418fe25SSong Gao     HWCAP_LOONGARCH_CRC32    = (1 << 6),
12663418fe25SSong Gao     HWCAP_LOONGARCH_COMPLEX  = (1 << 7),
12673418fe25SSong Gao     HWCAP_LOONGARCH_CRYPTO   = (1 << 8),
12683418fe25SSong Gao     HWCAP_LOONGARCH_LVZ      = (1 << 9),
12693418fe25SSong Gao     HWCAP_LOONGARCH_LBT_X86  = (1 << 10),
12703418fe25SSong Gao     HWCAP_LOONGARCH_LBT_ARM  = (1 << 11),
12713418fe25SSong Gao     HWCAP_LOONGARCH_LBT_MIPS = (1 << 12),
12723418fe25SSong Gao };
12733418fe25SSong Gao 
12743418fe25SSong Gao static uint32_t get_elf_hwcap(void)
12753418fe25SSong Gao {
12763418fe25SSong Gao     LoongArchCPU *cpu = LOONGARCH_CPU(thread_cpu);
12773418fe25SSong Gao     uint32_t hwcaps = 0;
12783418fe25SSong Gao 
12793418fe25SSong Gao     hwcaps |= HWCAP_LOONGARCH_CRC32;
12803418fe25SSong Gao 
12813418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[1], CPUCFG1, UAL)) {
12823418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_UAL;
12833418fe25SSong Gao     }
12843418fe25SSong Gao 
12853418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, FP)) {
12863418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_FPU;
12873418fe25SSong Gao     }
12883418fe25SSong Gao 
12893418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LAM)) {
12903418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_LAM;
12913418fe25SSong Gao     }
12923418fe25SSong Gao 
1293a9f6004fSJiajie Chen     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
1294a9f6004fSJiajie Chen         hwcaps |= HWCAP_LOONGARCH_LSX;
1295a9f6004fSJiajie Chen     }
1296a9f6004fSJiajie Chen 
1297a9f6004fSJiajie Chen     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) {
1298a9f6004fSJiajie Chen         hwcaps |= HWCAP_LOONGARCH_LASX;
1299a9f6004fSJiajie Chen     }
1300a9f6004fSJiajie Chen 
13013418fe25SSong Gao     return hwcaps;
13023418fe25SSong Gao }
13033418fe25SSong Gao 
13043418fe25SSong Gao #define ELF_PLATFORM "loongarch"
13053418fe25SSong Gao 
13063418fe25SSong Gao #endif /* TARGET_LOONGARCH64 */
13073418fe25SSong Gao 
1308048f6b4dSbellard #ifdef TARGET_MIPS
1309048f6b4dSbellard 
1310388bb21aSths #ifdef TARGET_MIPS64
1311388bb21aSths #define ELF_CLASS   ELFCLASS64
1312388bb21aSths #else
1313048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
1314388bb21aSths #endif
1315048f6b4dSbellard #define ELF_ARCH    EM_MIPS
1316872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
1317048f6b4dSbellard 
1318ace3d654SCarlo Marcelo Arenas Belón #ifdef TARGET_ABI_MIPSN32
1319ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) ((x) & EF_MIPS_ABI2)
1320ace3d654SCarlo Marcelo Arenas Belón #else
1321ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (!((x) & EF_MIPS_ABI2))
1322ace3d654SCarlo Marcelo Arenas Belón #endif
1323ace3d654SCarlo Marcelo Arenas Belón 
1324fbf47c18SJiaxun Yang #define ELF_BASE_PLATFORM get_elf_base_platform()
1325fbf47c18SJiaxun Yang 
1326fbf47c18SJiaxun Yang #define MATCH_PLATFORM_INSN(_flags, _base_platform)      \
1327fbf47c18SJiaxun Yang     do { if ((cpu->env.insn_flags & (_flags)) == _flags) \
1328fbf47c18SJiaxun Yang     { return _base_platform; } } while (0)
1329fbf47c18SJiaxun Yang 
1330fbf47c18SJiaxun Yang static const char *get_elf_base_platform(void)
1331fbf47c18SJiaxun Yang {
1332fbf47c18SJiaxun Yang     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
1333fbf47c18SJiaxun Yang 
1334fbf47c18SJiaxun Yang     /* 64 bit ISAs goes first */
1335fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R6, "mips64r6");
1336fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R5, "mips64r5");
1337fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R2, "mips64r2");
1338fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R1, "mips64");
1339fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS5, "mips5");
1340fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS4, "mips4");
1341fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS3, "mips3");
1342fbf47c18SJiaxun Yang 
1343fbf47c18SJiaxun Yang     /* 32 bit ISAs */
1344fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R6, "mips32r6");
1345fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R5, "mips32r5");
1346fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R2, "mips32r2");
1347fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R1, "mips32");
1348fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS2, "mips2");
1349fbf47c18SJiaxun Yang 
1350fbf47c18SJiaxun Yang     /* Fallback */
1351fbf47c18SJiaxun Yang     return "mips";
1352fbf47c18SJiaxun Yang }
1353fbf47c18SJiaxun Yang #undef MATCH_PLATFORM_INSN
1354fbf47c18SJiaxun Yang 
1355d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1356d97ef72eSRichard Henderson                                struct image_info *infop)
1357048f6b4dSbellard {
1358623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
1359048f6b4dSbellard     regs->cp0_epc = infop->entry;
1360048f6b4dSbellard     regs->regs[29] = infop->start_stack;
1361048f6b4dSbellard }
1362048f6b4dSbellard 
136351e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/elf.h.  */
136451e52606SNathan Froyd #define ELF_NREG 45
136551e52606SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
136651e52606SNathan Froyd 
136751e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/reg.h.  */
136851e52606SNathan Froyd enum {
136951e52606SNathan Froyd #ifdef TARGET_MIPS64
137051e52606SNathan Froyd     TARGET_EF_R0 = 0,
137151e52606SNathan Froyd #else
137251e52606SNathan Froyd     TARGET_EF_R0 = 6,
137351e52606SNathan Froyd #endif
137451e52606SNathan Froyd     TARGET_EF_R26 = TARGET_EF_R0 + 26,
137551e52606SNathan Froyd     TARGET_EF_R27 = TARGET_EF_R0 + 27,
137651e52606SNathan Froyd     TARGET_EF_LO = TARGET_EF_R0 + 32,
137751e52606SNathan Froyd     TARGET_EF_HI = TARGET_EF_R0 + 33,
137851e52606SNathan Froyd     TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
137951e52606SNathan Froyd     TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
138051e52606SNathan Froyd     TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
138151e52606SNathan Froyd     TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
138251e52606SNathan Froyd };
138351e52606SNathan Froyd 
138451e52606SNathan Froyd /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
138505390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMIPSState *env)
138651e52606SNathan Froyd {
138751e52606SNathan Froyd     int i;
138851e52606SNathan Froyd 
138951e52606SNathan Froyd     for (i = 0; i < TARGET_EF_R0; i++) {
139051e52606SNathan Froyd         (*regs)[i] = 0;
139151e52606SNathan Froyd     }
139251e52606SNathan Froyd     (*regs)[TARGET_EF_R0] = 0;
139351e52606SNathan Froyd 
139451e52606SNathan Froyd     for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
1395a29f998dSPaolo Bonzini         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]);
139651e52606SNathan Froyd     }
139751e52606SNathan Froyd 
139851e52606SNathan Froyd     (*regs)[TARGET_EF_R26] = 0;
139951e52606SNathan Froyd     (*regs)[TARGET_EF_R27] = 0;
1400a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_LO] = tswapreg(env->active_tc.LO[0]);
1401a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_HI] = tswapreg(env->active_tc.HI[0]);
1402a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_EPC] = tswapreg(env->active_tc.PC);
1403a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_BADVADDR] = tswapreg(env->CP0_BadVAddr);
1404a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_STATUS] = tswapreg(env->CP0_Status);
1405a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_CAUSE] = tswapreg(env->CP0_Cause);
140651e52606SNathan Froyd }
140751e52606SNathan Froyd 
140851e52606SNathan Froyd #define USE_ELF_CORE_DUMP
1409388bb21aSths #define ELF_EXEC_PAGESIZE        4096
1410388bb21aSths 
141146a1ee4fSJames Cowgill /* See arch/mips/include/uapi/asm/hwcap.h.  */
141246a1ee4fSJames Cowgill enum {
141346a1ee4fSJames Cowgill     HWCAP_MIPS_R6           = (1 << 0),
141446a1ee4fSJames Cowgill     HWCAP_MIPS_MSA          = (1 << 1),
14159ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_CRC32        = (1 << 2),
14169ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16       = (1 << 3),
14179ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MDMX         = (1 << 4),
14189ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS3D       = (1 << 5),
14199ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_SMARTMIPS    = (1 << 6),
14209ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP          = (1 << 7),
14219ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP2         = (1 << 8),
14229ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP3         = (1 << 9),
14239ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16E2     = (1 << 10),
14249ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_MMI      = (1 << 11),
14259ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT      = (1 << 12),
14269ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT2     = (1 << 13),
14279ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_CPUCFG   = (1 << 14),
142846a1ee4fSJames Cowgill };
142946a1ee4fSJames Cowgill 
143046a1ee4fSJames Cowgill #define ELF_HWCAP get_elf_hwcap()
143146a1ee4fSJames Cowgill 
14327d9a3d96SPhilippe Mathieu-Daudé #define GET_FEATURE_INSN(_flag, _hwcap) \
14336dd97bfcSPhilippe Mathieu-Daudé     do { if (cpu->env.insn_flags & (_flag)) { hwcaps |= _hwcap; } } while (0)
14346dd97bfcSPhilippe Mathieu-Daudé 
1435388765a0SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_SET(_reg, _mask, _hwcap) \
1436388765a0SPhilippe Mathieu-Daudé     do { if (cpu->env._reg & (_mask)) { hwcaps |= _hwcap; } } while (0)
1437388765a0SPhilippe Mathieu-Daudé 
1438ce543844SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_EQU(_reg, _start, _length, _val, _hwcap) \
1439ce543844SPhilippe Mathieu-Daudé     do { \
1440ce543844SPhilippe Mathieu-Daudé         if (extract32(cpu->env._reg, (_start), (_length)) == (_val)) { \
1441ce543844SPhilippe Mathieu-Daudé             hwcaps |= _hwcap; \
1442ce543844SPhilippe Mathieu-Daudé         } \
1443ce543844SPhilippe Mathieu-Daudé     } while (0)
1444ce543844SPhilippe Mathieu-Daudé 
144546a1ee4fSJames Cowgill static uint32_t get_elf_hwcap(void)
144646a1ee4fSJames Cowgill {
144746a1ee4fSJames Cowgill     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
144846a1ee4fSJames Cowgill     uint32_t hwcaps = 0;
144946a1ee4fSJames Cowgill 
1450ce543844SPhilippe Mathieu-Daudé     GET_FEATURE_REG_EQU(CP0_Config0, CP0C0_AR, CP0C0_AR_LENGTH,
1451ce543844SPhilippe Mathieu-Daudé                         2, HWCAP_MIPS_R6);
1452388765a0SPhilippe Mathieu-Daudé     GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA);
145353673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LMMI, HWCAP_LOONGSON_MMI);
145453673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LEXT, HWCAP_LOONGSON_EXT);
145546a1ee4fSJames Cowgill 
145646a1ee4fSJames Cowgill     return hwcaps;
145746a1ee4fSJames Cowgill }
145846a1ee4fSJames Cowgill 
1459ce543844SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_EQU
1460388765a0SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_SET
14617d9a3d96SPhilippe Mathieu-Daudé #undef GET_FEATURE_INSN
14626dd97bfcSPhilippe Mathieu-Daudé 
1463048f6b4dSbellard #endif /* TARGET_MIPS */
1464048f6b4dSbellard 
1465b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
1466b779e29eSEdgar E. Iglesias 
14670d5d4699SEdgar E. Iglesias #define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
1468b779e29eSEdgar E. Iglesias 
1469b779e29eSEdgar E. Iglesias #define ELF_CLASS   ELFCLASS32
14700d5d4699SEdgar E. Iglesias #define ELF_ARCH    EM_MICROBLAZE
1471b779e29eSEdgar E. Iglesias 
1472d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1473d97ef72eSRichard Henderson                                struct image_info *infop)
1474b779e29eSEdgar E. Iglesias {
1475b779e29eSEdgar E. Iglesias     regs->pc = infop->entry;
1476b779e29eSEdgar E. Iglesias     regs->r1 = infop->start_stack;
1477b779e29eSEdgar E. Iglesias 
1478b779e29eSEdgar E. Iglesias }
1479b779e29eSEdgar E. Iglesias 
1480b779e29eSEdgar E. Iglesias #define ELF_EXEC_PAGESIZE        4096
1481b779e29eSEdgar E. Iglesias 
1482e4cbd44dSEdgar E. Iglesias #define USE_ELF_CORE_DUMP
1483e4cbd44dSEdgar E. Iglesias #define ELF_NREG 38
1484e4cbd44dSEdgar E. Iglesias typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1485e4cbd44dSEdgar E. Iglesias 
1486e4cbd44dSEdgar E. Iglesias /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
148705390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env)
1488e4cbd44dSEdgar E. Iglesias {
1489e4cbd44dSEdgar E. Iglesias     int i, pos = 0;
1490e4cbd44dSEdgar E. Iglesias 
1491e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 32; i++) {
149286cd7b2dSPaolo Bonzini         (*regs)[pos++] = tswapreg(env->regs[i]);
1493e4cbd44dSEdgar E. Iglesias     }
1494e4cbd44dSEdgar E. Iglesias 
1495af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->pc);
14961074c0fbSRichard Henderson     (*regs)[pos++] = tswapreg(mb_cpu_read_msr(env));
1497af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1498af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->ear);
1499af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1500af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->esr);
1501e4cbd44dSEdgar E. Iglesias }
1502e4cbd44dSEdgar E. Iglesias 
1503b779e29eSEdgar E. Iglesias #endif /* TARGET_MICROBLAZE */
1504b779e29eSEdgar E. Iglesias 
1505a0a839b6SMarek Vasut #ifdef TARGET_NIOS2
1506a0a839b6SMarek Vasut 
1507a0a839b6SMarek Vasut #define elf_check_arch(x) ((x) == EM_ALTERA_NIOS2)
1508a0a839b6SMarek Vasut 
1509a0a839b6SMarek Vasut #define ELF_CLASS   ELFCLASS32
1510a0a839b6SMarek Vasut #define ELF_ARCH    EM_ALTERA_NIOS2
1511a0a839b6SMarek Vasut 
1512a0a839b6SMarek Vasut static void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1513a0a839b6SMarek Vasut {
1514a0a839b6SMarek Vasut     regs->ea = infop->entry;
1515a0a839b6SMarek Vasut     regs->sp = infop->start_stack;
1516a0a839b6SMarek Vasut }
1517a0a839b6SMarek Vasut 
1518f5ef0e51SRichard Henderson #define LO_COMMPAGE  TARGET_PAGE_SIZE
1519f5ef0e51SRichard Henderson 
1520f5ef0e51SRichard Henderson static bool init_guest_commpage(void)
1521f5ef0e51SRichard Henderson {
1522f5ef0e51SRichard Henderson     static const uint8_t kuser_page[4 + 2 * 64] = {
1523f5ef0e51SRichard Henderson         /* __kuser_helper_version */
1524f5ef0e51SRichard Henderson         [0x00] = 0x02, 0x00, 0x00, 0x00,
1525f5ef0e51SRichard Henderson 
1526f5ef0e51SRichard Henderson         /* __kuser_cmpxchg */
1527f5ef0e51SRichard Henderson         [0x04] = 0x3a, 0x6c, 0x3b, 0x00,  /* trap 16 */
1528f5ef0e51SRichard Henderson                  0x3a, 0x28, 0x00, 0xf8,  /* ret */
1529f5ef0e51SRichard Henderson 
1530f5ef0e51SRichard Henderson         /* __kuser_sigtramp */
1531f5ef0e51SRichard Henderson         [0x44] = 0xc4, 0x22, 0x80, 0x00,  /* movi r2, __NR_rt_sigreturn */
1532f5ef0e51SRichard Henderson                  0x3a, 0x68, 0x3b, 0x00,  /* trap 0 */
1533f5ef0e51SRichard Henderson     };
1534f5ef0e51SRichard Henderson 
1535f5ef0e51SRichard Henderson     void *want = g2h_untagged(LO_COMMPAGE & -qemu_host_page_size);
1536f5ef0e51SRichard Henderson     void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
1537f5ef0e51SRichard Henderson                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1538f5ef0e51SRichard Henderson 
1539f5ef0e51SRichard Henderson     if (addr == MAP_FAILED) {
1540f5ef0e51SRichard Henderson         perror("Allocating guest commpage");
1541f5ef0e51SRichard Henderson         exit(EXIT_FAILURE);
1542f5ef0e51SRichard Henderson     }
1543f5ef0e51SRichard Henderson     if (addr != want) {
1544f5ef0e51SRichard Henderson         return false;
1545f5ef0e51SRichard Henderson     }
1546f5ef0e51SRichard Henderson 
1547f5ef0e51SRichard Henderson     memcpy(addr, kuser_page, sizeof(kuser_page));
1548f5ef0e51SRichard Henderson 
1549f5ef0e51SRichard Henderson     if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
1550f5ef0e51SRichard Henderson         perror("Protecting guest commpage");
1551f5ef0e51SRichard Henderson         exit(EXIT_FAILURE);
1552f5ef0e51SRichard Henderson     }
1553f5ef0e51SRichard Henderson 
155449840a4aSRichard Henderson     page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
1555f5ef0e51SRichard Henderson                    PAGE_READ | PAGE_EXEC | PAGE_VALID);
1556f5ef0e51SRichard Henderson     return true;
1557f5ef0e51SRichard Henderson }
1558f5ef0e51SRichard Henderson 
1559a0a839b6SMarek Vasut #define ELF_EXEC_PAGESIZE        4096
1560a0a839b6SMarek Vasut 
1561a0a839b6SMarek Vasut #define USE_ELF_CORE_DUMP
1562a0a839b6SMarek Vasut #define ELF_NREG 49
1563a0a839b6SMarek Vasut typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1564a0a839b6SMarek Vasut 
1565a0a839b6SMarek Vasut /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
1566a0a839b6SMarek Vasut static void elf_core_copy_regs(target_elf_gregset_t *regs,
1567a0a839b6SMarek Vasut                                const CPUNios2State *env)
1568a0a839b6SMarek Vasut {
1569a0a839b6SMarek Vasut     int i;
1570a0a839b6SMarek Vasut 
1571a0a839b6SMarek Vasut     (*regs)[0] = -1;
1572a0a839b6SMarek Vasut     for (i = 1; i < 8; i++)    /* r0-r7 */
1573a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1574a0a839b6SMarek Vasut 
1575a0a839b6SMarek Vasut     for (i = 8; i < 16; i++)   /* r8-r15 */
1576a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i - 8]);
1577a0a839b6SMarek Vasut 
1578a0a839b6SMarek Vasut     for (i = 16; i < 24; i++)  /* r16-r23 */
1579a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1580a0a839b6SMarek Vasut     (*regs)[24] = -1;    /* R_ET */
1581a0a839b6SMarek Vasut     (*regs)[25] = -1;    /* R_BT */
1582a0a839b6SMarek Vasut     (*regs)[26] = tswapreg(env->regs[R_GP]);
1583a0a839b6SMarek Vasut     (*regs)[27] = tswapreg(env->regs[R_SP]);
1584a0a839b6SMarek Vasut     (*regs)[28] = tswapreg(env->regs[R_FP]);
1585a0a839b6SMarek Vasut     (*regs)[29] = tswapreg(env->regs[R_EA]);
1586a0a839b6SMarek Vasut     (*regs)[30] = -1;    /* R_SSTATUS */
1587a0a839b6SMarek Vasut     (*regs)[31] = tswapreg(env->regs[R_RA]);
1588a0a839b6SMarek Vasut 
158917a406eeSRichard Henderson     (*regs)[32] = tswapreg(env->pc);
1590a0a839b6SMarek Vasut 
1591a0a839b6SMarek Vasut     (*regs)[33] = -1; /* R_STATUS */
1592a0a839b6SMarek Vasut     (*regs)[34] = tswapreg(env->regs[CR_ESTATUS]);
1593a0a839b6SMarek Vasut 
1594a0a839b6SMarek Vasut     for (i = 35; i < 49; i++)    /* ... */
1595a0a839b6SMarek Vasut         (*regs)[i] = -1;
1596a0a839b6SMarek Vasut }
1597a0a839b6SMarek Vasut 
1598a0a839b6SMarek Vasut #endif /* TARGET_NIOS2 */
1599a0a839b6SMarek Vasut 
1600d962783eSJia Liu #ifdef TARGET_OPENRISC
1601d962783eSJia Liu 
1602d962783eSJia Liu #define ELF_ARCH EM_OPENRISC
1603d962783eSJia Liu #define ELF_CLASS ELFCLASS32
1604d962783eSJia Liu #define ELF_DATA  ELFDATA2MSB
1605d962783eSJia Liu 
1606d962783eSJia Liu static inline void init_thread(struct target_pt_regs *regs,
1607d962783eSJia Liu                                struct image_info *infop)
1608d962783eSJia Liu {
1609d962783eSJia Liu     regs->pc = infop->entry;
1610d962783eSJia Liu     regs->gpr[1] = infop->start_stack;
1611d962783eSJia Liu }
1612d962783eSJia Liu 
1613d962783eSJia Liu #define USE_ELF_CORE_DUMP
1614d962783eSJia Liu #define ELF_EXEC_PAGESIZE 8192
1615d962783eSJia Liu 
1616d962783eSJia Liu /* See linux kernel arch/openrisc/include/asm/elf.h.  */
1617d962783eSJia Liu #define ELF_NREG 34 /* gprs and pc, sr */
1618d962783eSJia Liu typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1619d962783eSJia Liu 
1620d962783eSJia Liu static void elf_core_copy_regs(target_elf_gregset_t *regs,
1621d962783eSJia Liu                                const CPUOpenRISCState *env)
1622d962783eSJia Liu {
1623d962783eSJia Liu     int i;
1624d962783eSJia Liu 
1625d962783eSJia Liu     for (i = 0; i < 32; i++) {
1626d89e71e8SStafford Horne         (*regs)[i] = tswapreg(cpu_get_gpr(env, i));
1627d962783eSJia Liu     }
162886cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->pc);
162984775c43SRichard Henderson     (*regs)[33] = tswapreg(cpu_get_sr(env));
1630d962783eSJia Liu }
1631d962783eSJia Liu #define ELF_HWCAP 0
1632d962783eSJia Liu #define ELF_PLATFORM NULL
1633d962783eSJia Liu 
1634d962783eSJia Liu #endif /* TARGET_OPENRISC */
1635d962783eSJia Liu 
1636fdf9b3e8Sbellard #ifdef TARGET_SH4
1637fdf9b3e8Sbellard 
1638fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
1639fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
1640fdf9b3e8Sbellard 
1641d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1642d97ef72eSRichard Henderson                                struct image_info *infop)
1643fdf9b3e8Sbellard {
1644fdf9b3e8Sbellard     /* Check other registers XXXXX */
1645fdf9b3e8Sbellard     regs->pc = infop->entry;
1646072ae847Sths     regs->regs[15] = infop->start_stack;
1647fdf9b3e8Sbellard }
1648fdf9b3e8Sbellard 
16497631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/elf.h.  */
16507631c97eSNathan Froyd #define ELF_NREG 23
16517631c97eSNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
16527631c97eSNathan Froyd 
16537631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/ptrace.h.  */
16547631c97eSNathan Froyd enum {
16557631c97eSNathan Froyd     TARGET_REG_PC = 16,
16567631c97eSNathan Froyd     TARGET_REG_PR = 17,
16577631c97eSNathan Froyd     TARGET_REG_SR = 18,
16587631c97eSNathan Froyd     TARGET_REG_GBR = 19,
16597631c97eSNathan Froyd     TARGET_REG_MACH = 20,
16607631c97eSNathan Froyd     TARGET_REG_MACL = 21,
16617631c97eSNathan Froyd     TARGET_REG_SYSCALL = 22
16627631c97eSNathan Froyd };
16637631c97eSNathan Froyd 
1664d97ef72eSRichard Henderson static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
166505390248SAndreas Färber                                       const CPUSH4State *env)
16667631c97eSNathan Froyd {
16677631c97eSNathan Froyd     int i;
16687631c97eSNathan Froyd 
16697631c97eSNathan Froyd     for (i = 0; i < 16; i++) {
167072cd500bSPhilippe Mathieu-Daudé         (*regs)[i] = tswapreg(env->gregs[i]);
16717631c97eSNathan Froyd     }
16727631c97eSNathan Froyd 
167386cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
167486cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PR] = tswapreg(env->pr);
167586cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_SR] = tswapreg(env->sr);
167686cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_GBR] = tswapreg(env->gbr);
167786cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACH] = tswapreg(env->mach);
167886cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACL] = tswapreg(env->macl);
16797631c97eSNathan Froyd     (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
16807631c97eSNathan Froyd }
16817631c97eSNathan Froyd 
16827631c97eSNathan Froyd #define USE_ELF_CORE_DUMP
1683fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
1684fdf9b3e8Sbellard 
1685e42fd944SRichard Henderson enum {
1686e42fd944SRichard Henderson     SH_CPU_HAS_FPU            = 0x0001, /* Hardware FPU support */
1687e42fd944SRichard Henderson     SH_CPU_HAS_P2_FLUSH_BUG   = 0x0002, /* Need to flush the cache in P2 area */
1688e42fd944SRichard Henderson     SH_CPU_HAS_MMU_PAGE_ASSOC = 0x0004, /* SH3: TLB way selection bit support */
1689e42fd944SRichard Henderson     SH_CPU_HAS_DSP            = 0x0008, /* SH-DSP: DSP support */
1690e42fd944SRichard Henderson     SH_CPU_HAS_PERF_COUNTER   = 0x0010, /* Hardware performance counters */
1691e42fd944SRichard Henderson     SH_CPU_HAS_PTEA           = 0x0020, /* PTEA register */
1692e42fd944SRichard Henderson     SH_CPU_HAS_LLSC           = 0x0040, /* movli.l/movco.l */
1693e42fd944SRichard Henderson     SH_CPU_HAS_L2_CACHE       = 0x0080, /* Secondary cache / URAM */
1694e42fd944SRichard Henderson     SH_CPU_HAS_OP32           = 0x0100, /* 32-bit instruction support */
1695e42fd944SRichard Henderson     SH_CPU_HAS_PTEAEX         = 0x0200, /* PTE ASID Extension support */
1696e42fd944SRichard Henderson };
1697e42fd944SRichard Henderson 
1698e42fd944SRichard Henderson #define ELF_HWCAP get_elf_hwcap()
1699e42fd944SRichard Henderson 
1700e42fd944SRichard Henderson static uint32_t get_elf_hwcap(void)
1701e42fd944SRichard Henderson {
1702e42fd944SRichard Henderson     SuperHCPU *cpu = SUPERH_CPU(thread_cpu);
1703e42fd944SRichard Henderson     uint32_t hwcap = 0;
1704e42fd944SRichard Henderson 
1705e42fd944SRichard Henderson     hwcap |= SH_CPU_HAS_FPU;
1706e42fd944SRichard Henderson 
1707e42fd944SRichard Henderson     if (cpu->env.features & SH_FEATURE_SH4A) {
1708e42fd944SRichard Henderson         hwcap |= SH_CPU_HAS_LLSC;
1709e42fd944SRichard Henderson     }
1710e42fd944SRichard Henderson 
1711e42fd944SRichard Henderson     return hwcap;
1712e42fd944SRichard Henderson }
1713e42fd944SRichard Henderson 
1714fdf9b3e8Sbellard #endif
1715fdf9b3e8Sbellard 
171648733d19Sths #ifdef TARGET_CRIS
171748733d19Sths 
171848733d19Sths #define ELF_CLASS ELFCLASS32
171948733d19Sths #define ELF_ARCH  EM_CRIS
172048733d19Sths 
1721d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1722d97ef72eSRichard Henderson                                struct image_info *infop)
172348733d19Sths {
172448733d19Sths     regs->erp = infop->entry;
172548733d19Sths }
172648733d19Sths 
172748733d19Sths #define ELF_EXEC_PAGESIZE        8192
172848733d19Sths 
172948733d19Sths #endif
173048733d19Sths 
1731e6e5906bSpbrook #ifdef TARGET_M68K
1732e6e5906bSpbrook 
1733e6e5906bSpbrook #define ELF_CLASS       ELFCLASS32
1734e6e5906bSpbrook #define ELF_ARCH        EM_68K
1735e6e5906bSpbrook 
1736e6e5906bSpbrook /* ??? Does this need to do anything?
1737e6e5906bSpbrook    #define ELF_PLAT_INIT(_r) */
1738e6e5906bSpbrook 
1739d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1740d97ef72eSRichard Henderson                                struct image_info *infop)
1741e6e5906bSpbrook {
1742e6e5906bSpbrook     regs->usp = infop->start_stack;
1743e6e5906bSpbrook     regs->sr = 0;
1744e6e5906bSpbrook     regs->pc = infop->entry;
1745e6e5906bSpbrook }
1746e6e5906bSpbrook 
17477a93cc55SNathan Froyd /* See linux kernel: arch/m68k/include/asm/elf.h.  */
17487a93cc55SNathan Froyd #define ELF_NREG 20
17497a93cc55SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
17507a93cc55SNathan Froyd 
175105390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUM68KState *env)
17527a93cc55SNathan Froyd {
175386cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->dregs[1]);
175486cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->dregs[2]);
175586cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->dregs[3]);
175686cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->dregs[4]);
175786cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->dregs[5]);
175886cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->dregs[6]);
175986cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->dregs[7]);
176086cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->aregs[0]);
176186cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->aregs[1]);
176286cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->aregs[2]);
176386cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->aregs[3]);
176486cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->aregs[4]);
176586cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->aregs[5]);
176686cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->aregs[6]);
176786cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->dregs[0]);
176886cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->aregs[7]);
176986cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(env->dregs[0]); /* FIXME: orig_d0 */
177086cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->sr);
177186cd7b2dSPaolo Bonzini     (*regs)[18] = tswapreg(env->pc);
17727a93cc55SNathan Froyd     (*regs)[19] = 0;  /* FIXME: regs->format | regs->vector */
17737a93cc55SNathan Froyd }
17747a93cc55SNathan Froyd 
17757a93cc55SNathan Froyd #define USE_ELF_CORE_DUMP
1776e6e5906bSpbrook #define ELF_EXEC_PAGESIZE       8192
1777e6e5906bSpbrook 
1778e6e5906bSpbrook #endif
1779e6e5906bSpbrook 
17807a3148a9Sj_mayer #ifdef TARGET_ALPHA
17817a3148a9Sj_mayer 
17827a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
17837a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
17847a3148a9Sj_mayer 
1785d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1786d97ef72eSRichard Henderson                                struct image_info *infop)
17877a3148a9Sj_mayer {
17887a3148a9Sj_mayer     regs->pc = infop->entry;
17897a3148a9Sj_mayer     regs->ps = 8;
17907a3148a9Sj_mayer     regs->usp = infop->start_stack;
17917a3148a9Sj_mayer }
17927a3148a9Sj_mayer 
17937a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
17947a3148a9Sj_mayer 
17957a3148a9Sj_mayer #endif /* TARGET_ALPHA */
17967a3148a9Sj_mayer 
1797a4c075f1SUlrich Hecht #ifdef TARGET_S390X
1798a4c075f1SUlrich Hecht 
1799a4c075f1SUlrich Hecht #define ELF_CLASS	ELFCLASS64
1800a4c075f1SUlrich Hecht #define ELF_DATA	ELFDATA2MSB
1801a4c075f1SUlrich Hecht #define ELF_ARCH	EM_S390
1802a4c075f1SUlrich Hecht 
18036d88baf1SDavid Hildenbrand #include "elf.h"
18046d88baf1SDavid Hildenbrand 
18056d88baf1SDavid Hildenbrand #define ELF_HWCAP get_elf_hwcap()
18066d88baf1SDavid Hildenbrand 
18076d88baf1SDavid Hildenbrand #define GET_FEATURE(_feat, _hwcap) \
18086d88baf1SDavid Hildenbrand     do { if (s390_has_feat(_feat)) { hwcap |= _hwcap; } } while (0)
18096d88baf1SDavid Hildenbrand 
1810e1b819c8SIlya Leoshkevich uint32_t get_elf_hwcap(void)
18116d88baf1SDavid Hildenbrand {
18126d88baf1SDavid Hildenbrand     /*
18136d88baf1SDavid Hildenbrand      * Let's assume we always have esan3 and zarch.
18146d88baf1SDavid Hildenbrand      * 31-bit processes can use 64-bit registers (high gprs).
18156d88baf1SDavid Hildenbrand      */
18166d88baf1SDavid Hildenbrand     uint32_t hwcap = HWCAP_S390_ESAN3 | HWCAP_S390_ZARCH | HWCAP_S390_HIGH_GPRS;
18176d88baf1SDavid Hildenbrand 
18186d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_STFLE, HWCAP_S390_STFLE);
18196d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_MSA, HWCAP_S390_MSA);
18206d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_LONG_DISPLACEMENT, HWCAP_S390_LDISP);
18216d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_EXTENDED_IMMEDIATE, HWCAP_S390_EIMM);
18226d88baf1SDavid Hildenbrand     if (s390_has_feat(S390_FEAT_EXTENDED_TRANSLATION_3) &&
18236d88baf1SDavid Hildenbrand         s390_has_feat(S390_FEAT_ETF3_ENH)) {
18246d88baf1SDavid Hildenbrand         hwcap |= HWCAP_S390_ETF3EH;
18256d88baf1SDavid Hildenbrand     }
18266d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS);
1827da215c23SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR_ENH, HWCAP_S390_VXRS_EXT);
1828ffc8453bSIlya Leoshkevich     GET_FEATURE(S390_FEAT_VECTOR_ENH2, HWCAP_S390_VXRS_EXT2);
18296d88baf1SDavid Hildenbrand 
18306d88baf1SDavid Hildenbrand     return hwcap;
18316d88baf1SDavid Hildenbrand }
18326d88baf1SDavid Hildenbrand 
1833e19807beSIlya Leoshkevich const char *elf_hwcap_str(uint32_t bit)
1834e19807beSIlya Leoshkevich {
1835e19807beSIlya Leoshkevich     static const char *hwcap_str[] = {
18367f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ESAN3]     = "esan3",
18377f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ZARCH]     = "zarch",
18387f114a58SIlya Leoshkevich         [HWCAP_S390_NR_STFLE]     = "stfle",
18397f114a58SIlya Leoshkevich         [HWCAP_S390_NR_MSA]       = "msa",
18407f114a58SIlya Leoshkevich         [HWCAP_S390_NR_LDISP]     = "ldisp",
18417f114a58SIlya Leoshkevich         [HWCAP_S390_NR_EIMM]      = "eimm",
18427f114a58SIlya Leoshkevich         [HWCAP_S390_NR_DFP]       = "dfp",
18437f114a58SIlya Leoshkevich         [HWCAP_S390_NR_HPAGE]     = "edat",
18447f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ETF3EH]    = "etf3eh",
18457f114a58SIlya Leoshkevich         [HWCAP_S390_NR_HIGH_GPRS] = "highgprs",
18467f114a58SIlya Leoshkevich         [HWCAP_S390_NR_TE]        = "te",
18477f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS]      = "vx",
18487f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_BCD]  = "vxd",
18497f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_EXT]  = "vxe",
18507f114a58SIlya Leoshkevich         [HWCAP_S390_NR_GS]        = "gs",
18517f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_EXT2] = "vxe2",
18527f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_PDE]  = "vxp",
18537f114a58SIlya Leoshkevich         [HWCAP_S390_NR_SORT]      = "sort",
18547f114a58SIlya Leoshkevich         [HWCAP_S390_NR_DFLT]      = "dflt",
18557f114a58SIlya Leoshkevich         [HWCAP_S390_NR_NNPA]      = "nnpa",
18567f114a58SIlya Leoshkevich         [HWCAP_S390_NR_PCI_MIO]   = "pcimio",
18577f114a58SIlya Leoshkevich         [HWCAP_S390_NR_SIE]       = "sie",
1858e19807beSIlya Leoshkevich     };
1859e19807beSIlya Leoshkevich 
1860e19807beSIlya Leoshkevich     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
1861e19807beSIlya Leoshkevich }
1862e19807beSIlya Leoshkevich 
1863a4c075f1SUlrich Hecht static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1864a4c075f1SUlrich Hecht {
1865a4c075f1SUlrich Hecht     regs->psw.addr = infop->entry;
186678a1e153SIlya Leoshkevich     regs->psw.mask = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | \
186778a1e153SIlya Leoshkevich                      PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_MASK_64 | \
186878a1e153SIlya Leoshkevich                      PSW_MASK_32;
1869a4c075f1SUlrich Hecht     regs->gprs[15] = infop->start_stack;
1870a4c075f1SUlrich Hecht }
1871a4c075f1SUlrich Hecht 
18724a1e8931SIlya Leoshkevich /* See linux kernel: arch/s390/include/uapi/asm/ptrace.h (s390_regs).  */
18734a1e8931SIlya Leoshkevich #define ELF_NREG 27
18744a1e8931SIlya Leoshkevich typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
18754a1e8931SIlya Leoshkevich 
18764a1e8931SIlya Leoshkevich enum {
18774a1e8931SIlya Leoshkevich     TARGET_REG_PSWM = 0,
18784a1e8931SIlya Leoshkevich     TARGET_REG_PSWA = 1,
18794a1e8931SIlya Leoshkevich     TARGET_REG_GPRS = 2,
18804a1e8931SIlya Leoshkevich     TARGET_REG_ARS = 18,
18814a1e8931SIlya Leoshkevich     TARGET_REG_ORIG_R2 = 26,
18824a1e8931SIlya Leoshkevich };
18834a1e8931SIlya Leoshkevich 
18844a1e8931SIlya Leoshkevich static void elf_core_copy_regs(target_elf_gregset_t *regs,
18854a1e8931SIlya Leoshkevich                                const CPUS390XState *env)
18864a1e8931SIlya Leoshkevich {
18874a1e8931SIlya Leoshkevich     int i;
18884a1e8931SIlya Leoshkevich     uint32_t *aregs;
18894a1e8931SIlya Leoshkevich 
18904a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWM] = tswapreg(env->psw.mask);
18914a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWA] = tswapreg(env->psw.addr);
18924a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
18934a1e8931SIlya Leoshkevich         (*regs)[TARGET_REG_GPRS + i] = tswapreg(env->regs[i]);
18944a1e8931SIlya Leoshkevich     }
18954a1e8931SIlya Leoshkevich     aregs = (uint32_t *)&((*regs)[TARGET_REG_ARS]);
18964a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
18974a1e8931SIlya Leoshkevich         aregs[i] = tswap32(env->aregs[i]);
18984a1e8931SIlya Leoshkevich     }
18994a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_ORIG_R2] = 0;
19004a1e8931SIlya Leoshkevich }
19014a1e8931SIlya Leoshkevich 
19024a1e8931SIlya Leoshkevich #define USE_ELF_CORE_DUMP
19034a1e8931SIlya Leoshkevich #define ELF_EXEC_PAGESIZE 4096
19044a1e8931SIlya Leoshkevich 
1905b63c6b97SRichard Henderson #define VDSO_HEADER "vdso.c.inc"
1906b63c6b97SRichard Henderson 
1907a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
1908a4c075f1SUlrich Hecht 
190947ae93cdSMichael Clark #ifdef TARGET_RISCV
191047ae93cdSMichael Clark 
191147ae93cdSMichael Clark #define ELF_ARCH  EM_RISCV
191247ae93cdSMichael Clark 
191347ae93cdSMichael Clark #ifdef TARGET_RISCV32
191447ae93cdSMichael Clark #define ELF_CLASS ELFCLASS32
1915468c1bb5SRichard Henderson #define VDSO_HEADER "vdso-32.c.inc"
191647ae93cdSMichael Clark #else
191747ae93cdSMichael Clark #define ELF_CLASS ELFCLASS64
1918468c1bb5SRichard Henderson #define VDSO_HEADER "vdso-64.c.inc"
191947ae93cdSMichael Clark #endif
192047ae93cdSMichael Clark 
1921cb46938cSKito Cheng #define ELF_HWCAP get_elf_hwcap()
1922cb46938cSKito Cheng 
1923cb46938cSKito Cheng static uint32_t get_elf_hwcap(void)
1924cb46938cSKito Cheng {
1925cb46938cSKito Cheng #define MISA_BIT(EXT) (1 << (EXT - 'A'))
1926cb46938cSKito Cheng     RISCVCPU *cpu = RISCV_CPU(thread_cpu);
1927cb46938cSKito Cheng     uint32_t mask = MISA_BIT('I') | MISA_BIT('M') | MISA_BIT('A')
19284333f092SNathan Egge                     | MISA_BIT('F') | MISA_BIT('D') | MISA_BIT('C')
19294333f092SNathan Egge                     | MISA_BIT('V');
1930cb46938cSKito Cheng 
1931e91a7227SRichard Henderson     return cpu->env.misa_ext & mask;
1932cb46938cSKito Cheng #undef MISA_BIT
1933cb46938cSKito Cheng }
1934cb46938cSKito Cheng 
193547ae93cdSMichael Clark static inline void init_thread(struct target_pt_regs *regs,
193647ae93cdSMichael Clark                                struct image_info *infop)
193747ae93cdSMichael Clark {
193847ae93cdSMichael Clark     regs->sepc = infop->entry;
193947ae93cdSMichael Clark     regs->sp = infop->start_stack;
194047ae93cdSMichael Clark }
194147ae93cdSMichael Clark 
194247ae93cdSMichael Clark #define ELF_EXEC_PAGESIZE 4096
194347ae93cdSMichael Clark 
194447ae93cdSMichael Clark #endif /* TARGET_RISCV */
194547ae93cdSMichael Clark 
19467c248bcdSRichard Henderson #ifdef TARGET_HPPA
19477c248bcdSRichard Henderson 
19487c248bcdSRichard Henderson #define ELF_CLASS       ELFCLASS32
19497c248bcdSRichard Henderson #define ELF_ARCH        EM_PARISC
19507c248bcdSRichard Henderson #define ELF_PLATFORM    "PARISC"
19517c248bcdSRichard Henderson #define STACK_GROWS_DOWN 0
19527c248bcdSRichard Henderson #define STACK_ALIGNMENT  64
19537c248bcdSRichard Henderson 
1954c7bc2a8fSRichard Henderson #define VDSO_HEADER "vdso.c.inc"
1955c7bc2a8fSRichard Henderson 
19567c248bcdSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
19577c248bcdSRichard Henderson                                struct image_info *infop)
19587c248bcdSRichard Henderson {
19597c248bcdSRichard Henderson     regs->iaoq[0] = infop->entry;
19607c248bcdSRichard Henderson     regs->iaoq[1] = infop->entry + 4;
19617c248bcdSRichard Henderson     regs->gr[23] = 0;
196260f1c801SRichard Henderson     regs->gr[24] = infop->argv;
196360f1c801SRichard Henderson     regs->gr[25] = infop->argc;
19647c248bcdSRichard Henderson     /* The top-of-stack contains a linkage buffer.  */
19657c248bcdSRichard Henderson     regs->gr[30] = infop->start_stack + 64;
19667c248bcdSRichard Henderson     regs->gr[31] = infop->entry;
19677c248bcdSRichard Henderson }
19687c248bcdSRichard Henderson 
1969eee816c0SRichard Henderson #define LO_COMMPAGE  0
1970eee816c0SRichard Henderson 
1971eee816c0SRichard Henderson static bool init_guest_commpage(void)
1972eee816c0SRichard Henderson {
1973eee816c0SRichard Henderson     void *want = g2h_untagged(LO_COMMPAGE);
1974eee816c0SRichard Henderson     void *addr = mmap(want, qemu_host_page_size, PROT_NONE,
1975eee816c0SRichard Henderson                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1976eee816c0SRichard Henderson 
1977eee816c0SRichard Henderson     if (addr == MAP_FAILED) {
1978eee816c0SRichard Henderson         perror("Allocating guest commpage");
1979eee816c0SRichard Henderson         exit(EXIT_FAILURE);
1980eee816c0SRichard Henderson     }
1981eee816c0SRichard Henderson     if (addr != want) {
1982eee816c0SRichard Henderson         return false;
1983eee816c0SRichard Henderson     }
1984eee816c0SRichard Henderson 
1985eee816c0SRichard Henderson     /*
1986eee816c0SRichard Henderson      * On Linux, page zero is normally marked execute only + gateway.
1987eee816c0SRichard Henderson      * Normal read or write is supposed to fail (thus PROT_NONE above),
1988eee816c0SRichard Henderson      * but specific offsets have kernel code mapped to raise permissions
1989eee816c0SRichard Henderson      * and implement syscalls.  Here, simply mark the page executable.
1990eee816c0SRichard Henderson      * Special case the entry points during translation (see do_page_zero).
1991eee816c0SRichard Henderson      */
199249840a4aSRichard Henderson     page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
1993eee816c0SRichard Henderson                    PAGE_EXEC | PAGE_VALID);
1994eee816c0SRichard Henderson     return true;
1995eee816c0SRichard Henderson }
1996eee816c0SRichard Henderson 
19977c248bcdSRichard Henderson #endif /* TARGET_HPPA */
19987c248bcdSRichard Henderson 
1999ba7651fbSMax Filippov #ifdef TARGET_XTENSA
2000ba7651fbSMax Filippov 
2001ba7651fbSMax Filippov #define ELF_CLASS       ELFCLASS32
2002ba7651fbSMax Filippov #define ELF_ARCH        EM_XTENSA
2003ba7651fbSMax Filippov 
2004ba7651fbSMax Filippov static inline void init_thread(struct target_pt_regs *regs,
2005ba7651fbSMax Filippov                                struct image_info *infop)
2006ba7651fbSMax Filippov {
2007ba7651fbSMax Filippov     regs->windowbase = 0;
2008ba7651fbSMax Filippov     regs->windowstart = 1;
2009ba7651fbSMax Filippov     regs->areg[1] = infop->start_stack;
2010ba7651fbSMax Filippov     regs->pc = infop->entry;
2011d2796be6SMax Filippov     if (info_is_fdpic(infop)) {
2012d2796be6SMax Filippov         regs->areg[4] = infop->loadmap_addr;
2013d2796be6SMax Filippov         regs->areg[5] = infop->interpreter_loadmap_addr;
2014d2796be6SMax Filippov         if (infop->interpreter_loadmap_addr) {
2015d2796be6SMax Filippov             regs->areg[6] = infop->interpreter_pt_dynamic_addr;
2016d2796be6SMax Filippov         } else {
2017d2796be6SMax Filippov             regs->areg[6] = infop->pt_dynamic_addr;
2018d2796be6SMax Filippov         }
2019d2796be6SMax Filippov     }
2020ba7651fbSMax Filippov }
2021ba7651fbSMax Filippov 
2022ba7651fbSMax Filippov /* See linux kernel: arch/xtensa/include/asm/elf.h.  */
2023ba7651fbSMax Filippov #define ELF_NREG 128
2024ba7651fbSMax Filippov typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
2025ba7651fbSMax Filippov 
2026ba7651fbSMax Filippov enum {
2027ba7651fbSMax Filippov     TARGET_REG_PC,
2028ba7651fbSMax Filippov     TARGET_REG_PS,
2029ba7651fbSMax Filippov     TARGET_REG_LBEG,
2030ba7651fbSMax Filippov     TARGET_REG_LEND,
2031ba7651fbSMax Filippov     TARGET_REG_LCOUNT,
2032ba7651fbSMax Filippov     TARGET_REG_SAR,
2033ba7651fbSMax Filippov     TARGET_REG_WINDOWSTART,
2034ba7651fbSMax Filippov     TARGET_REG_WINDOWBASE,
2035ba7651fbSMax Filippov     TARGET_REG_THREADPTR,
2036ba7651fbSMax Filippov     TARGET_REG_AR0 = 64,
2037ba7651fbSMax Filippov };
2038ba7651fbSMax Filippov 
2039ba7651fbSMax Filippov static void elf_core_copy_regs(target_elf_gregset_t *regs,
2040ba7651fbSMax Filippov                                const CPUXtensaState *env)
2041ba7651fbSMax Filippov {
2042ba7651fbSMax Filippov     unsigned i;
2043ba7651fbSMax Filippov 
2044ba7651fbSMax Filippov     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
2045ba7651fbSMax Filippov     (*regs)[TARGET_REG_PS] = tswapreg(env->sregs[PS] & ~PS_EXCM);
2046ba7651fbSMax Filippov     (*regs)[TARGET_REG_LBEG] = tswapreg(env->sregs[LBEG]);
2047ba7651fbSMax Filippov     (*regs)[TARGET_REG_LEND] = tswapreg(env->sregs[LEND]);
2048ba7651fbSMax Filippov     (*regs)[TARGET_REG_LCOUNT] = tswapreg(env->sregs[LCOUNT]);
2049ba7651fbSMax Filippov     (*regs)[TARGET_REG_SAR] = tswapreg(env->sregs[SAR]);
2050ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWSTART] = tswapreg(env->sregs[WINDOW_START]);
2051ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWBASE] = tswapreg(env->sregs[WINDOW_BASE]);
2052ba7651fbSMax Filippov     (*regs)[TARGET_REG_THREADPTR] = tswapreg(env->uregs[THREADPTR]);
2053ba7651fbSMax Filippov     xtensa_sync_phys_from_window((CPUXtensaState *)env);
2054ba7651fbSMax Filippov     for (i = 0; i < env->config->nareg; ++i) {
2055ba7651fbSMax Filippov         (*regs)[TARGET_REG_AR0 + i] = tswapreg(env->phys_regs[i]);
2056ba7651fbSMax Filippov     }
2057ba7651fbSMax Filippov }
2058ba7651fbSMax Filippov 
2059ba7651fbSMax Filippov #define USE_ELF_CORE_DUMP
2060ba7651fbSMax Filippov #define ELF_EXEC_PAGESIZE       4096
2061ba7651fbSMax Filippov 
2062ba7651fbSMax Filippov #endif /* TARGET_XTENSA */
2063ba7651fbSMax Filippov 
2064d2a56bd2STaylor Simpson #ifdef TARGET_HEXAGON
2065d2a56bd2STaylor Simpson 
2066d2a56bd2STaylor Simpson #define ELF_CLASS       ELFCLASS32
2067d2a56bd2STaylor Simpson #define ELF_ARCH        EM_HEXAGON
2068d2a56bd2STaylor Simpson 
2069d2a56bd2STaylor Simpson static inline void init_thread(struct target_pt_regs *regs,
2070d2a56bd2STaylor Simpson                                struct image_info *infop)
2071d2a56bd2STaylor Simpson {
2072d2a56bd2STaylor Simpson     regs->sepc = infop->entry;
2073d2a56bd2STaylor Simpson     regs->sp = infop->start_stack;
2074d2a56bd2STaylor Simpson }
2075d2a56bd2STaylor Simpson 
2076d2a56bd2STaylor Simpson #endif /* TARGET_HEXAGON */
2077d2a56bd2STaylor Simpson 
2078fcdc0ab4SJiaxun Yang #ifndef ELF_BASE_PLATFORM
2079fcdc0ab4SJiaxun Yang #define ELF_BASE_PLATFORM (NULL)
2080fcdc0ab4SJiaxun Yang #endif
2081fcdc0ab4SJiaxun Yang 
208215338fd7Sbellard #ifndef ELF_PLATFORM
208315338fd7Sbellard #define ELF_PLATFORM (NULL)
208415338fd7Sbellard #endif
208515338fd7Sbellard 
208675be901cSPeter Crosthwaite #ifndef ELF_MACHINE
208775be901cSPeter Crosthwaite #define ELF_MACHINE ELF_ARCH
208875be901cSPeter Crosthwaite #endif
208975be901cSPeter Crosthwaite 
2090d276a604SPeter Crosthwaite #ifndef elf_check_arch
2091d276a604SPeter Crosthwaite #define elf_check_arch(x) ((x) == ELF_ARCH)
2092d276a604SPeter Crosthwaite #endif
2093d276a604SPeter Crosthwaite 
2094ace3d654SCarlo Marcelo Arenas Belón #ifndef elf_check_abi
2095ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (1)
2096ace3d654SCarlo Marcelo Arenas Belón #endif
2097ace3d654SCarlo Marcelo Arenas Belón 
209815338fd7Sbellard #ifndef ELF_HWCAP
209915338fd7Sbellard #define ELF_HWCAP 0
210015338fd7Sbellard #endif
210115338fd7Sbellard 
21027c4ee5bcSRichard Henderson #ifndef STACK_GROWS_DOWN
21037c4ee5bcSRichard Henderson #define STACK_GROWS_DOWN 1
21047c4ee5bcSRichard Henderson #endif
21057c4ee5bcSRichard Henderson 
21067c4ee5bcSRichard Henderson #ifndef STACK_ALIGNMENT
21077c4ee5bcSRichard Henderson #define STACK_ALIGNMENT 16
21087c4ee5bcSRichard Henderson #endif
21097c4ee5bcSRichard Henderson 
2110992f48a0Sblueswir1 #ifdef TARGET_ABI32
2111cb33da57Sblueswir1 #undef ELF_CLASS
2112992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
2113cb33da57Sblueswir1 #undef bswaptls
2114cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
2115cb33da57Sblueswir1 #endif
2116cb33da57Sblueswir1 
2117872f3d04SRichard Henderson #ifndef EXSTACK_DEFAULT
2118872f3d04SRichard Henderson #define EXSTACK_DEFAULT false
2119872f3d04SRichard Henderson #endif
2120872f3d04SRichard Henderson 
212131e31b8aSbellard #include "elf.h"
212209bfb054Sbellard 
2123e8384b37SRichard Henderson /* We must delay the following stanzas until after "elf.h". */
2124e8384b37SRichard Henderson #if defined(TARGET_AARCH64)
2125e8384b37SRichard Henderson 
2126e8384b37SRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
2127e8384b37SRichard Henderson                                     const uint32_t *data,
2128e8384b37SRichard Henderson                                     struct image_info *info,
2129e8384b37SRichard Henderson                                     Error **errp)
2130e8384b37SRichard Henderson {
2131e8384b37SRichard Henderson     if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
2132e8384b37SRichard Henderson         if (pr_datasz != sizeof(uint32_t)) {
2133e8384b37SRichard Henderson             error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
2134e8384b37SRichard Henderson             return false;
2135e8384b37SRichard Henderson         }
2136e8384b37SRichard Henderson         /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
2137e8384b37SRichard Henderson         info->note_flags = *data;
2138e8384b37SRichard Henderson     }
2139e8384b37SRichard Henderson     return true;
2140e8384b37SRichard Henderson }
2141e8384b37SRichard Henderson #define ARCH_USE_GNU_PROPERTY 1
2142e8384b37SRichard Henderson 
2143e8384b37SRichard Henderson #else
2144e8384b37SRichard Henderson 
214583f990ebSRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
214683f990ebSRichard Henderson                                     const uint32_t *data,
214783f990ebSRichard Henderson                                     struct image_info *info,
214883f990ebSRichard Henderson                                     Error **errp)
214983f990ebSRichard Henderson {
215083f990ebSRichard Henderson     g_assert_not_reached();
215183f990ebSRichard Henderson }
215283f990ebSRichard Henderson #define ARCH_USE_GNU_PROPERTY 0
215383f990ebSRichard Henderson 
2154e8384b37SRichard Henderson #endif
2155e8384b37SRichard Henderson 
215609bfb054Sbellard struct exec
215709bfb054Sbellard {
215809bfb054Sbellard     unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
215909bfb054Sbellard     unsigned int a_text;   /* length of text, in bytes */
216009bfb054Sbellard     unsigned int a_data;   /* length of data, in bytes */
216109bfb054Sbellard     unsigned int a_bss;    /* length of uninitialized data area, in bytes */
216209bfb054Sbellard     unsigned int a_syms;   /* length of symbol table data in file, in bytes */
216309bfb054Sbellard     unsigned int a_entry;  /* start address */
216409bfb054Sbellard     unsigned int a_trsize; /* length of relocation info for text, in bytes */
216509bfb054Sbellard     unsigned int a_drsize; /* length of relocation info for data, in bytes */
216609bfb054Sbellard };
216709bfb054Sbellard 
216809bfb054Sbellard 
216909bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
217009bfb054Sbellard #define OMAGIC 0407
217109bfb054Sbellard #define NMAGIC 0410
217209bfb054Sbellard #define ZMAGIC 0413
217309bfb054Sbellard #define QMAGIC 0314
217409bfb054Sbellard 
2175e0d1673dSLirong Yuan #define DLINFO_ITEMS 16
217631e31b8aSbellard 
217709bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
217809bfb054Sbellard {
217909bfb054Sbellard     memcpy(to, from, n);
218009bfb054Sbellard }
218109bfb054Sbellard 
218231e31b8aSbellard #ifdef BSWAP_NEEDED
218392a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
218431e31b8aSbellard {
218531e31b8aSbellard     bswap16s(&ehdr->e_type);            /* Object file type */
218631e31b8aSbellard     bswap16s(&ehdr->e_machine);         /* Architecture */
218731e31b8aSbellard     bswap32s(&ehdr->e_version);         /* Object file version */
218892a31b1fSbellard     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
218992a31b1fSbellard     bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
219092a31b1fSbellard     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
219131e31b8aSbellard     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
219231e31b8aSbellard     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
219331e31b8aSbellard     bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
219431e31b8aSbellard     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
219531e31b8aSbellard     bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
219631e31b8aSbellard     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
219731e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
219831e31b8aSbellard }
219931e31b8aSbellard 
2200991f8f0cSRichard Henderson static void bswap_phdr(struct elf_phdr *phdr, int phnum)
220131e31b8aSbellard {
2202991f8f0cSRichard Henderson     int i;
2203991f8f0cSRichard Henderson     for (i = 0; i < phnum; ++i, ++phdr) {
220431e31b8aSbellard         bswap32s(&phdr->p_type);        /* Segment type */
2205991f8f0cSRichard Henderson         bswap32s(&phdr->p_flags);       /* Segment flags */
220692a31b1fSbellard         bswaptls(&phdr->p_offset);      /* Segment file offset */
220792a31b1fSbellard         bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
220892a31b1fSbellard         bswaptls(&phdr->p_paddr);       /* Segment physical address */
220992a31b1fSbellard         bswaptls(&phdr->p_filesz);      /* Segment size in file */
221092a31b1fSbellard         bswaptls(&phdr->p_memsz);       /* Segment size in memory */
221192a31b1fSbellard         bswaptls(&phdr->p_align);       /* Segment alignment */
221231e31b8aSbellard     }
2213991f8f0cSRichard Henderson }
2214689f936fSbellard 
2215991f8f0cSRichard Henderson static void bswap_shdr(struct elf_shdr *shdr, int shnum)
2216689f936fSbellard {
2217991f8f0cSRichard Henderson     int i;
2218991f8f0cSRichard Henderson     for (i = 0; i < shnum; ++i, ++shdr) {
2219689f936fSbellard         bswap32s(&shdr->sh_name);
2220689f936fSbellard         bswap32s(&shdr->sh_type);
222192a31b1fSbellard         bswaptls(&shdr->sh_flags);
222292a31b1fSbellard         bswaptls(&shdr->sh_addr);
222392a31b1fSbellard         bswaptls(&shdr->sh_offset);
222492a31b1fSbellard         bswaptls(&shdr->sh_size);
2225689f936fSbellard         bswap32s(&shdr->sh_link);
2226689f936fSbellard         bswap32s(&shdr->sh_info);
222792a31b1fSbellard         bswaptls(&shdr->sh_addralign);
222892a31b1fSbellard         bswaptls(&shdr->sh_entsize);
2229689f936fSbellard     }
2230991f8f0cSRichard Henderson }
2231689f936fSbellard 
22327a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
2233689f936fSbellard {
2234689f936fSbellard     bswap32s(&sym->st_name);
22357a3148a9Sj_mayer     bswaptls(&sym->st_value);
22367a3148a9Sj_mayer     bswaptls(&sym->st_size);
2237689f936fSbellard     bswap16s(&sym->st_shndx);
2238689f936fSbellard }
22395dd0db52SStefan Markovic 
22405dd0db52SStefan Markovic #ifdef TARGET_MIPS
22415dd0db52SStefan Markovic static void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags)
22425dd0db52SStefan Markovic {
22435dd0db52SStefan Markovic     bswap16s(&abiflags->version);
22445dd0db52SStefan Markovic     bswap32s(&abiflags->ases);
22455dd0db52SStefan Markovic     bswap32s(&abiflags->isa_ext);
22465dd0db52SStefan Markovic     bswap32s(&abiflags->flags1);
22475dd0db52SStefan Markovic     bswap32s(&abiflags->flags2);
22485dd0db52SStefan Markovic }
22495dd0db52SStefan Markovic #endif
2250991f8f0cSRichard Henderson #else
2251991f8f0cSRichard Henderson static inline void bswap_ehdr(struct elfhdr *ehdr) { }
2252991f8f0cSRichard Henderson static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
2253991f8f0cSRichard Henderson static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
2254991f8f0cSRichard Henderson static inline void bswap_sym(struct elf_sym *sym) { }
22555dd0db52SStefan Markovic #ifdef TARGET_MIPS
22565dd0db52SStefan Markovic static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { }
22575dd0db52SStefan Markovic #endif
225831e31b8aSbellard #endif
225931e31b8aSbellard 
2260edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
22619349b4f9SAndreas Färber static int elf_core_dump(int, const CPUArchState *);
2262edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
226386cf82dcSRichard Henderson static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
226486cf82dcSRichard Henderson                          abi_ulong load_bias);
2265edf8e2afSMika Westerberg 
22669058abddSRichard Henderson /* Verify the portions of EHDR within E_IDENT for the target.
22679058abddSRichard Henderson    This can be performed before bswapping the entire header.  */
22689058abddSRichard Henderson static bool elf_check_ident(struct elfhdr *ehdr)
22699058abddSRichard Henderson {
22709058abddSRichard Henderson     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
22719058abddSRichard Henderson             && ehdr->e_ident[EI_MAG1] == ELFMAG1
22729058abddSRichard Henderson             && ehdr->e_ident[EI_MAG2] == ELFMAG2
22739058abddSRichard Henderson             && ehdr->e_ident[EI_MAG3] == ELFMAG3
22749058abddSRichard Henderson             && ehdr->e_ident[EI_CLASS] == ELF_CLASS
22759058abddSRichard Henderson             && ehdr->e_ident[EI_DATA] == ELF_DATA
22769058abddSRichard Henderson             && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
22779058abddSRichard Henderson }
22789058abddSRichard Henderson 
22799058abddSRichard Henderson /* Verify the portions of EHDR outside of E_IDENT for the target.
22809058abddSRichard Henderson    This has to wait until after bswapping the header.  */
22819058abddSRichard Henderson static bool elf_check_ehdr(struct elfhdr *ehdr)
22829058abddSRichard Henderson {
22839058abddSRichard Henderson     return (elf_check_arch(ehdr->e_machine)
2284ace3d654SCarlo Marcelo Arenas Belón             && elf_check_abi(ehdr->e_flags)
22859058abddSRichard Henderson             && ehdr->e_ehsize == sizeof(struct elfhdr)
22869058abddSRichard Henderson             && ehdr->e_phentsize == sizeof(struct elf_phdr)
22879058abddSRichard Henderson             && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
22889058abddSRichard Henderson }
22899058abddSRichard Henderson 
229031e31b8aSbellard /*
2291e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
229231e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
229331e31b8aSbellard  * to be put directly into the top of new user memory.
229431e31b8aSbellard  *
229531e31b8aSbellard  */
229659baae9aSStefan Brüns static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch,
229759baae9aSStefan Brüns                                   abi_ulong p, abi_ulong stack_limit)
229831e31b8aSbellard {
229959baae9aSStefan Brüns     char *tmp;
23007c4ee5bcSRichard Henderson     int len, i;
230159baae9aSStefan Brüns     abi_ulong top = p;
230231e31b8aSbellard 
230331e31b8aSbellard     if (!p) {
230431e31b8aSbellard         return 0;       /* bullet-proofing */
230531e31b8aSbellard     }
230659baae9aSStefan Brüns 
23077c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
23087c4ee5bcSRichard Henderson         int offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
23097c4ee5bcSRichard Henderson         for (i = argc - 1; i >= 0; --i) {
23107c4ee5bcSRichard Henderson             tmp = argv[i];
2311edf779ffSbellard             if (!tmp) {
231231e31b8aSbellard                 fprintf(stderr, "VFS: argc is wrong");
231331e31b8aSbellard                 exit(-1);
231431e31b8aSbellard             }
231559baae9aSStefan Brüns             len = strlen(tmp) + 1;
231659baae9aSStefan Brüns             tmp += len;
231759baae9aSStefan Brüns 
231859baae9aSStefan Brüns             if (len > (p - stack_limit)) {
231931e31b8aSbellard                 return 0;
232031e31b8aSbellard             }
232131e31b8aSbellard             while (len) {
232231e31b8aSbellard                 int bytes_to_copy = (len > offset) ? offset : len;
232331e31b8aSbellard                 tmp -= bytes_to_copy;
232431e31b8aSbellard                 p -= bytes_to_copy;
232531e31b8aSbellard                 offset -= bytes_to_copy;
232631e31b8aSbellard                 len -= bytes_to_copy;
232759baae9aSStefan Brüns 
232859baae9aSStefan Brüns                 memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
232959baae9aSStefan Brüns 
233059baae9aSStefan Brüns                 if (offset == 0) {
233159baae9aSStefan Brüns                     memcpy_to_target(p, scratch, top - p);
233259baae9aSStefan Brüns                     top = p;
233359baae9aSStefan Brüns                     offset = TARGET_PAGE_SIZE;
233431e31b8aSbellard                 }
233531e31b8aSbellard             }
233631e31b8aSbellard         }
23377c4ee5bcSRichard Henderson         if (p != top) {
233859baae9aSStefan Brüns             memcpy_to_target(p, scratch + offset, top - p);
233959baae9aSStefan Brüns         }
23407c4ee5bcSRichard Henderson     } else {
23417c4ee5bcSRichard Henderson         int remaining = TARGET_PAGE_SIZE - (p % TARGET_PAGE_SIZE);
23427c4ee5bcSRichard Henderson         for (i = 0; i < argc; ++i) {
23437c4ee5bcSRichard Henderson             tmp = argv[i];
23447c4ee5bcSRichard Henderson             if (!tmp) {
23457c4ee5bcSRichard Henderson                 fprintf(stderr, "VFS: argc is wrong");
23467c4ee5bcSRichard Henderson                 exit(-1);
23477c4ee5bcSRichard Henderson             }
23487c4ee5bcSRichard Henderson             len = strlen(tmp) + 1;
23497c4ee5bcSRichard Henderson             if (len > (stack_limit - p)) {
23507c4ee5bcSRichard Henderson                 return 0;
23517c4ee5bcSRichard Henderson             }
23527c4ee5bcSRichard Henderson             while (len) {
23537c4ee5bcSRichard Henderson                 int bytes_to_copy = (len > remaining) ? remaining : len;
23547c4ee5bcSRichard Henderson 
23557c4ee5bcSRichard Henderson                 memcpy_fromfs(scratch + (p - top), tmp, bytes_to_copy);
23567c4ee5bcSRichard Henderson 
23577c4ee5bcSRichard Henderson                 tmp += bytes_to_copy;
23587c4ee5bcSRichard Henderson                 remaining -= bytes_to_copy;
23597c4ee5bcSRichard Henderson                 p += bytes_to_copy;
23607c4ee5bcSRichard Henderson                 len -= bytes_to_copy;
23617c4ee5bcSRichard Henderson 
23627c4ee5bcSRichard Henderson                 if (remaining == 0) {
23637c4ee5bcSRichard Henderson                     memcpy_to_target(top, scratch, p - top);
23647c4ee5bcSRichard Henderson                     top = p;
23657c4ee5bcSRichard Henderson                     remaining = TARGET_PAGE_SIZE;
23667c4ee5bcSRichard Henderson                 }
23677c4ee5bcSRichard Henderson             }
23687c4ee5bcSRichard Henderson         }
23697c4ee5bcSRichard Henderson         if (p != top) {
23707c4ee5bcSRichard Henderson             memcpy_to_target(top, scratch, p - top);
23717c4ee5bcSRichard Henderson         }
23727c4ee5bcSRichard Henderson     }
237359baae9aSStefan Brüns 
237431e31b8aSbellard     return p;
237531e31b8aSbellard }
237631e31b8aSbellard 
237759baae9aSStefan Brüns /* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of
237859baae9aSStefan Brüns  * argument/environment space. Newer kernels (>2.6.33) allow more,
237959baae9aSStefan Brüns  * dependent on stack size, but guarantee at least 32 pages for
238059baae9aSStefan Brüns  * backwards compatibility.
238159baae9aSStefan Brüns  */
238259baae9aSStefan Brüns #define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE)
238359baae9aSStefan Brüns 
238459baae9aSStefan Brüns static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
238531e31b8aSbellard                                  struct image_info *info)
238631e31b8aSbellard {
238759baae9aSStefan Brüns     abi_ulong size, error, guard;
2388872f3d04SRichard Henderson     int prot;
238931e31b8aSbellard 
2390703e0e89SRichard Henderson     size = guest_stack_size;
239159baae9aSStefan Brüns     if (size < STACK_LOWER_LIMIT) {
239259baae9aSStefan Brüns         size = STACK_LOWER_LIMIT;
239360dcbcb5SRichard Henderson     }
2394f4388205SHelge Deller 
2395f4388205SHelge Deller     if (STACK_GROWS_DOWN) {
239660dcbcb5SRichard Henderson         guard = TARGET_PAGE_SIZE;
23978e3b0cbbSMarc-André Lureau         if (guard < qemu_real_host_page_size()) {
23988e3b0cbbSMarc-André Lureau             guard = qemu_real_host_page_size();
239960dcbcb5SRichard Henderson         }
2400f4388205SHelge Deller     } else {
2401f4388205SHelge Deller         /* no guard page for hppa target where stack grows upwards. */
2402f4388205SHelge Deller         guard = 0;
2403f4388205SHelge Deller     }
240460dcbcb5SRichard Henderson 
2405872f3d04SRichard Henderson     prot = PROT_READ | PROT_WRITE;
2406872f3d04SRichard Henderson     if (info->exec_stack) {
2407872f3d04SRichard Henderson         prot |= PROT_EXEC;
2408872f3d04SRichard Henderson     }
2409872f3d04SRichard Henderson     error = target_mmap(0, size + guard, prot,
241060dcbcb5SRichard Henderson                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
241109bfb054Sbellard     if (error == -1) {
241260dcbcb5SRichard Henderson         perror("mmap stack");
241331e31b8aSbellard         exit(-1);
241431e31b8aSbellard     }
241531e31b8aSbellard 
241660dcbcb5SRichard Henderson     /* We reserve one extra page at the top of the stack as guard.  */
24177c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
241860dcbcb5SRichard Henderson         target_mprotect(error, guard, PROT_NONE);
241960dcbcb5SRichard Henderson         info->stack_limit = error + guard;
242059baae9aSStefan Brüns         return info->stack_limit + size - sizeof(void *);
24217c4ee5bcSRichard Henderson     } else {
24227c4ee5bcSRichard Henderson         info->stack_limit = error + size;
24237c4ee5bcSRichard Henderson         return error;
24247c4ee5bcSRichard Henderson     }
242531e31b8aSbellard }
242631e31b8aSbellard 
24272d385be6SRichard Henderson /**
24282d385be6SRichard Henderson  * zero_bss:
24292d385be6SRichard Henderson  *
24302d385be6SRichard Henderson  * Map and zero the bss.  We need to explicitly zero any fractional pages
24312d385be6SRichard Henderson  * after the data section (i.e. bss).  Return false on mapping failure.
24322d385be6SRichard Henderson  */
2433e6e66b03SRichard Henderson static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss,
2434e6e66b03SRichard Henderson                      int prot, Error **errp)
243531e31b8aSbellard {
24362d385be6SRichard Henderson     abi_ulong align_bss;
2437cf129f3aSRichard Henderson 
2438e6e66b03SRichard Henderson     /* We only expect writable bss; the code segment shouldn't need this. */
2439e6e66b03SRichard Henderson     if (!(prot & PROT_WRITE)) {
2440e6e66b03SRichard Henderson         error_setg(errp, "PT_LOAD with non-writable bss");
2441e6e66b03SRichard Henderson         return false;
2442e6e66b03SRichard Henderson     }
2443e6e66b03SRichard Henderson 
24442d385be6SRichard Henderson     align_bss = TARGET_PAGE_ALIGN(start_bss);
24452d385be6SRichard Henderson     end_bss = TARGET_PAGE_ALIGN(end_bss);
2446cf129f3aSRichard Henderson 
24472d385be6SRichard Henderson     if (start_bss < align_bss) {
24482d385be6SRichard Henderson         int flags = page_get_flags(start_bss);
2449cf129f3aSRichard Henderson 
2450e6e66b03SRichard Henderson         if (!(flags & PAGE_BITS)) {
2451e6e66b03SRichard Henderson             /*
2452e6e66b03SRichard Henderson              * The whole address space of the executable was reserved
2453e6e66b03SRichard Henderson              * at the start, therefore all pages will be VALID.
2454e6e66b03SRichard Henderson              * But assuming there are no PROT_NONE PT_LOAD segments,
2455e6e66b03SRichard Henderson              * a PROT_NONE page means no data all bss, and we can
2456e6e66b03SRichard Henderson              * simply extend the new anon mapping back to the start
2457e6e66b03SRichard Henderson              * of the page of bss.
2458e6e66b03SRichard Henderson              */
24592d385be6SRichard Henderson             align_bss -= TARGET_PAGE_SIZE;
24602d385be6SRichard Henderson         } else {
2461e6e66b03SRichard Henderson             /*
2462e6e66b03SRichard Henderson              * The start of the bss shares a page with something.
2463e6e66b03SRichard Henderson              * The only thing that we expect is the data section,
2464e6e66b03SRichard Henderson              * which would already be marked writable.
2465e6e66b03SRichard Henderson              * Overlapping the RX code segment seems malformed.
2466e6e66b03SRichard Henderson              */
2467e6e66b03SRichard Henderson             if (!(flags & PAGE_WRITE)) {
2468e6e66b03SRichard Henderson                 error_setg(errp, "PT_LOAD with bss overlapping "
2469e6e66b03SRichard Henderson                            "non-writable page");
2470e6e66b03SRichard Henderson                 return false;
2471e6e66b03SRichard Henderson             }
2472e6e66b03SRichard Henderson 
2473e6e66b03SRichard Henderson             /* The page is already mapped and writable. */
2474e6e66b03SRichard Henderson             memset(g2h_untagged(start_bss), 0, align_bss - start_bss);
247531e31b8aSbellard         }
2476f46e9a0bSTom Musta     }
2477cf129f3aSRichard Henderson 
2478e6e66b03SRichard Henderson     if (align_bss < end_bss &&
24792d385be6SRichard Henderson         target_mmap(align_bss, end_bss - align_bss, prot,
2480e6e66b03SRichard Henderson                     MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) {
2481e6e66b03SRichard Henderson         error_setg_errno(errp, errno, "Error mapping bss");
2482e6e66b03SRichard Henderson         return false;
2483e6e66b03SRichard Henderson     }
2484e6e66b03SRichard Henderson     return true;
2485853d6f7aSbellard }
2486853d6f7aSbellard 
2487d2796be6SMax Filippov #if defined(TARGET_ARM)
2488cf58affeSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2489cf58affeSChristophe Lyon {
2490cf58affeSChristophe Lyon     return exec->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC;
2491cf58affeSChristophe Lyon }
2492d2796be6SMax Filippov #elif defined(TARGET_XTENSA)
2493d2796be6SMax Filippov static int elf_is_fdpic(struct elfhdr *exec)
2494d2796be6SMax Filippov {
2495d2796be6SMax Filippov     return exec->e_ident[EI_OSABI] == ELFOSABI_XTENSA_FDPIC;
2496d2796be6SMax Filippov }
2497cf58affeSChristophe Lyon #else
2498a99856cdSChristophe Lyon /* Default implementation, always false.  */
2499a99856cdSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2500a99856cdSChristophe Lyon {
2501a99856cdSChristophe Lyon     return 0;
2502a99856cdSChristophe Lyon }
2503cf58affeSChristophe Lyon #endif
2504a99856cdSChristophe Lyon 
25051af02e83SMike Frysinger static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
25061af02e83SMike Frysinger {
25071af02e83SMike Frysinger     uint16_t n;
25081af02e83SMike Frysinger     struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
25091af02e83SMike Frysinger 
25101af02e83SMike Frysinger     /* elf32_fdpic_loadseg */
25111af02e83SMike Frysinger     n = info->nsegs;
25121af02e83SMike Frysinger     while (n--) {
25131af02e83SMike Frysinger         sp -= 12;
25141af02e83SMike Frysinger         put_user_u32(loadsegs[n].addr, sp+0);
25151af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_vaddr, sp+4);
25161af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_memsz, sp+8);
25171af02e83SMike Frysinger     }
25181af02e83SMike Frysinger 
25191af02e83SMike Frysinger     /* elf32_fdpic_loadmap */
25201af02e83SMike Frysinger     sp -= 4;
25211af02e83SMike Frysinger     put_user_u16(0, sp+0); /* version */
25221af02e83SMike Frysinger     put_user_u16(info->nsegs, sp+2); /* nsegs */
25231af02e83SMike Frysinger 
25241af02e83SMike Frysinger     info->personality = PER_LINUX_FDPIC;
25251af02e83SMike Frysinger     info->loadmap_addr = sp;
25261af02e83SMike Frysinger 
25271af02e83SMike Frysinger     return sp;
25281af02e83SMike Frysinger }
25291af02e83SMike Frysinger 
2530992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
253131e31b8aSbellard                                    struct elfhdr *exec,
25328e62a717SRichard Henderson                                    struct image_info *info,
2533c40f621aSRichard Henderson                                    struct image_info *interp_info,
2534c40f621aSRichard Henderson                                    struct image_info *vdso_info)
253531e31b8aSbellard {
2536992f48a0Sblueswir1     abi_ulong sp;
25377c4ee5bcSRichard Henderson     abi_ulong u_argc, u_argv, u_envp, u_auxv;
253853a5960aSpbrook     int size;
253914322badSLaurent ALFONSI     int i;
254014322badSLaurent ALFONSI     abi_ulong u_rand_bytes;
254114322badSLaurent ALFONSI     uint8_t k_rand_bytes[16];
2542fcdc0ab4SJiaxun Yang     abi_ulong u_platform, u_base_platform;
2543fcdc0ab4SJiaxun Yang     const char *k_platform, *k_base_platform;
2544863cf0b7Sj_mayer     const int n = sizeof(elf_addr_t);
254531e31b8aSbellard 
254653a5960aSpbrook     sp = p;
25471af02e83SMike Frysinger 
25481af02e83SMike Frysinger     /* Needs to be before we load the env/argc/... */
25491af02e83SMike Frysinger     if (elf_is_fdpic(exec)) {
25501af02e83SMike Frysinger         /* Need 4 byte alignment for these structs */
25511af02e83SMike Frysinger         sp &= ~3;
25521af02e83SMike Frysinger         sp = loader_build_fdpic_loadmap(info, sp);
25531af02e83SMike Frysinger         info->other_info = interp_info;
25541af02e83SMike Frysinger         if (interp_info) {
25551af02e83SMike Frysinger             interp_info->other_info = info;
25561af02e83SMike Frysinger             sp = loader_build_fdpic_loadmap(interp_info, sp);
25573cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = interp_info->loadmap_addr;
25583cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = interp_info->pt_dynamic_addr;
25593cb10cfaSChristophe Lyon         } else {
25603cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = 0;
25613cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = 0;
25621af02e83SMike Frysinger         }
25631af02e83SMike Frysinger     }
25641af02e83SMike Frysinger 
2565fcdc0ab4SJiaxun Yang     u_base_platform = 0;
2566fcdc0ab4SJiaxun Yang     k_base_platform = ELF_BASE_PLATFORM;
2567fcdc0ab4SJiaxun Yang     if (k_base_platform) {
2568fcdc0ab4SJiaxun Yang         size_t len = strlen(k_base_platform) + 1;
2569fcdc0ab4SJiaxun Yang         if (STACK_GROWS_DOWN) {
2570fcdc0ab4SJiaxun Yang             sp -= (len + n - 1) & ~(n - 1);
2571fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2572fcdc0ab4SJiaxun Yang             /* FIXME - check return value of memcpy_to_target() for failure */
2573fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2574fcdc0ab4SJiaxun Yang         } else {
2575fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2576fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2577fcdc0ab4SJiaxun Yang             sp += len + 1;
2578fcdc0ab4SJiaxun Yang         }
2579fcdc0ab4SJiaxun Yang     }
2580fcdc0ab4SJiaxun Yang 
258153a5960aSpbrook     u_platform = 0;
258215338fd7Sbellard     k_platform = ELF_PLATFORM;
258315338fd7Sbellard     if (k_platform) {
258415338fd7Sbellard         size_t len = strlen(k_platform) + 1;
25857c4ee5bcSRichard Henderson         if (STACK_GROWS_DOWN) {
258653a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
258753a5960aSpbrook             u_platform = sp;
2588579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
258953a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
25907c4ee5bcSRichard Henderson         } else {
25917c4ee5bcSRichard Henderson             memcpy_to_target(sp, k_platform, len);
25927c4ee5bcSRichard Henderson             u_platform = sp;
25937c4ee5bcSRichard Henderson             sp += len + 1;
25947c4ee5bcSRichard Henderson         }
25957c4ee5bcSRichard Henderson     }
25967c4ee5bcSRichard Henderson 
25977c4ee5bcSRichard Henderson     /* Provide 16 byte alignment for the PRNG, and basic alignment for
25987c4ee5bcSRichard Henderson      * the argv and envp pointers.
25997c4ee5bcSRichard Henderson      */
26007c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
26017c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_DOWN(sp, 16);
26027c4ee5bcSRichard Henderson     } else {
26037c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp, 16);
260415338fd7Sbellard     }
260514322badSLaurent ALFONSI 
260614322badSLaurent ALFONSI     /*
2607c6a2377fSRichard Henderson      * Generate 16 random bytes for userspace PRNG seeding.
260814322badSLaurent ALFONSI      */
2609c6a2377fSRichard Henderson     qemu_guest_getrandom_nofail(k_rand_bytes, sizeof(k_rand_bytes));
26107c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
261114322badSLaurent ALFONSI         sp -= 16;
261214322badSLaurent ALFONSI         u_rand_bytes = sp;
261314322badSLaurent ALFONSI         /* FIXME - check return value of memcpy_to_target() for failure */
261414322badSLaurent ALFONSI         memcpy_to_target(sp, k_rand_bytes, 16);
26157c4ee5bcSRichard Henderson     } else {
26167c4ee5bcSRichard Henderson         memcpy_to_target(sp, k_rand_bytes, 16);
26177c4ee5bcSRichard Henderson         u_rand_bytes = sp;
26187c4ee5bcSRichard Henderson         sp += 16;
26197c4ee5bcSRichard Henderson     }
262014322badSLaurent ALFONSI 
262153a5960aSpbrook     size = (DLINFO_ITEMS + 1) * 2;
2622c40f621aSRichard Henderson     if (k_base_platform) {
2623fcdc0ab4SJiaxun Yang         size += 2;
2624c40f621aSRichard Henderson     }
2625c40f621aSRichard Henderson     if (k_platform) {
262653a5960aSpbrook         size += 2;
2627c40f621aSRichard Henderson     }
2628c40f621aSRichard Henderson     if (vdso_info) {
2629c40f621aSRichard Henderson         size += 2;
2630c40f621aSRichard Henderson     }
2631f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
263253a5960aSpbrook     size += DLINFO_ARCH_ITEMS * 2;
2633f5155289Sbellard #endif
2634ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2635ad6919dcSPeter Maydell     size += 2;
2636ad6919dcSPeter Maydell #endif
2637f516511eSPeter Maydell     info->auxv_len = size * n;
2638f516511eSPeter Maydell 
263953a5960aSpbrook     size += envc + argc + 2;
2640b9329d4bSRichard Henderson     size += 1;  /* argc itself */
264153a5960aSpbrook     size *= n;
26427c4ee5bcSRichard Henderson 
26437c4ee5bcSRichard Henderson     /* Allocate space and finalize stack alignment for entry now.  */
26447c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
26457c4ee5bcSRichard Henderson         u_argc = QEMU_ALIGN_DOWN(sp - size, STACK_ALIGNMENT);
26467c4ee5bcSRichard Henderson         sp = u_argc;
26477c4ee5bcSRichard Henderson     } else {
26487c4ee5bcSRichard Henderson         u_argc = sp;
26497c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp + size, STACK_ALIGNMENT);
26507c4ee5bcSRichard Henderson     }
26517c4ee5bcSRichard Henderson 
26527c4ee5bcSRichard Henderson     u_argv = u_argc + n;
26537c4ee5bcSRichard Henderson     u_envp = u_argv + (argc + 1) * n;
26547c4ee5bcSRichard Henderson     u_auxv = u_envp + (envc + 1) * n;
26557c4ee5bcSRichard Henderson     info->saved_auxv = u_auxv;
265660f1c801SRichard Henderson     info->argc = argc;
265760f1c801SRichard Henderson     info->envc = envc;
265860f1c801SRichard Henderson     info->argv = u_argv;
265960f1c801SRichard Henderson     info->envp = u_envp;
2660f5155289Sbellard 
2661863cf0b7Sj_mayer     /* This is correct because Linux defines
2662863cf0b7Sj_mayer      * elf_addr_t as Elf32_Off / Elf64_Off
2663863cf0b7Sj_mayer      */
266453a5960aSpbrook #define NEW_AUX_ENT(id, val) do {               \
26657c4ee5bcSRichard Henderson         put_user_ual(id, u_auxv);  u_auxv += n; \
26667c4ee5bcSRichard Henderson         put_user_ual(val, u_auxv); u_auxv += n; \
266753a5960aSpbrook     } while(0)
26682f619698Sbellard 
266982991bedSPeter Maydell #ifdef ARCH_DLINFO
267082991bedSPeter Maydell     /*
267182991bedSPeter Maydell      * ARCH_DLINFO must come first so platform specific code can enforce
267282991bedSPeter Maydell      * special alignment requirements on the AUXV if necessary (eg. PPC).
267382991bedSPeter Maydell      */
267482991bedSPeter Maydell     ARCH_DLINFO;
267582991bedSPeter Maydell #endif
2676f516511eSPeter Maydell     /* There must be exactly DLINFO_ITEMS entries here, or the assert
2677f516511eSPeter Maydell      * on info->auxv_len will trigger.
2678f516511eSPeter Maydell      */
26798e62a717SRichard Henderson     NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
2680992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
2681992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
268233143c44SLaurent Vivier     if ((info->alignment & ~qemu_host_page_mask) != 0) {
268333143c44SLaurent Vivier         /* Target doesn't support host page size alignment */
268433143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
268533143c44SLaurent Vivier     } else {
268633143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(MAX(TARGET_PAGE_SIZE,
268733143c44SLaurent Vivier                                                qemu_host_page_size)));
268833143c44SLaurent Vivier     }
26898e62a717SRichard Henderson     NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
2690992f48a0Sblueswir1     NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
26918e62a717SRichard Henderson     NEW_AUX_ENT(AT_ENTRY, info->entry);
2692992f48a0Sblueswir1     NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
2693992f48a0Sblueswir1     NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
2694992f48a0Sblueswir1     NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
2695992f48a0Sblueswir1     NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
2696992f48a0Sblueswir1     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
2697a07c67dfSpbrook     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
269814322badSLaurent ALFONSI     NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
2699444cd5c3SMarco A L Barbosa     NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
2700e0d1673dSLirong Yuan     NEW_AUX_ENT(AT_EXECFN, info->file_string);
270114322badSLaurent ALFONSI 
2702ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2703ad6919dcSPeter Maydell     NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
2704ad6919dcSPeter Maydell #endif
2705ad6919dcSPeter Maydell 
2706fcdc0ab4SJiaxun Yang     if (u_base_platform) {
2707fcdc0ab4SJiaxun Yang         NEW_AUX_ENT(AT_BASE_PLATFORM, u_base_platform);
2708fcdc0ab4SJiaxun Yang     }
27097c4ee5bcSRichard Henderson     if (u_platform) {
271053a5960aSpbrook         NEW_AUX_ENT(AT_PLATFORM, u_platform);
27117c4ee5bcSRichard Henderson     }
2712c40f621aSRichard Henderson     if (vdso_info) {
2713c40f621aSRichard Henderson         NEW_AUX_ENT(AT_SYSINFO_EHDR, vdso_info->load_addr);
2714c40f621aSRichard Henderson     }
27157c4ee5bcSRichard Henderson     NEW_AUX_ENT (AT_NULL, 0);
2716f5155289Sbellard #undef NEW_AUX_ENT
2717f5155289Sbellard 
2718f516511eSPeter Maydell     /* Check that our initial calculation of the auxv length matches how much
2719f516511eSPeter Maydell      * we actually put into it.
2720f516511eSPeter Maydell      */
2721f516511eSPeter Maydell     assert(info->auxv_len == u_auxv - info->saved_auxv);
2722edf8e2afSMika Westerberg 
27237c4ee5bcSRichard Henderson     put_user_ual(argc, u_argc);
27247c4ee5bcSRichard Henderson 
27257c4ee5bcSRichard Henderson     p = info->arg_strings;
27267c4ee5bcSRichard Henderson     for (i = 0; i < argc; ++i) {
27277c4ee5bcSRichard Henderson         put_user_ual(p, u_argv);
27287c4ee5bcSRichard Henderson         u_argv += n;
27297c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
27307c4ee5bcSRichard Henderson     }
27317c4ee5bcSRichard Henderson     put_user_ual(0, u_argv);
27327c4ee5bcSRichard Henderson 
27337c4ee5bcSRichard Henderson     p = info->env_strings;
27347c4ee5bcSRichard Henderson     for (i = 0; i < envc; ++i) {
27357c4ee5bcSRichard Henderson         put_user_ual(p, u_envp);
27367c4ee5bcSRichard Henderson         u_envp += n;
27377c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
27387c4ee5bcSRichard Henderson     }
27397c4ee5bcSRichard Henderson     put_user_ual(0, u_envp);
27407c4ee5bcSRichard Henderson 
274131e31b8aSbellard     return sp;
274231e31b8aSbellard }
274331e31b8aSbellard 
2744f5ef0e51SRichard Henderson #if defined(HI_COMMPAGE)
2745eee816c0SRichard Henderson #define LO_COMMPAGE -1
2746f5ef0e51SRichard Henderson #elif defined(LO_COMMPAGE)
274766346fafSRichard Henderson #define HI_COMMPAGE 0
2748f5ef0e51SRichard Henderson #else
2749f5ef0e51SRichard Henderson #define HI_COMMPAGE 0
2750eee816c0SRichard Henderson #define LO_COMMPAGE -1
2751d461b73eSRichard Henderson #ifndef INIT_GUEST_COMMPAGE
2752ee947430SAlex Bennée #define init_guest_commpage() true
2753ee947430SAlex Bennée #endif
2754d461b73eSRichard Henderson #endif
2755ee947430SAlex Bennée 
275606f38c66SRichard Henderson /**
275706f38c66SRichard Henderson  * pgb_try_mmap:
275806f38c66SRichard Henderson  * @addr: host start address
275906f38c66SRichard Henderson  * @addr_last: host last address
276006f38c66SRichard Henderson  * @keep: do not unmap the probe region
276106f38c66SRichard Henderson  *
276206f38c66SRichard Henderson  * Return 1 if [@addr, @addr_last] is not mapped in the host,
276306f38c66SRichard Henderson  * return 0 if it is not available to map, and -1 on mmap error.
276406f38c66SRichard Henderson  * If @keep, the region is left mapped on success, otherwise unmapped.
276506f38c66SRichard Henderson  */
276606f38c66SRichard Henderson static int pgb_try_mmap(uintptr_t addr, uintptr_t addr_last, bool keep)
276706f38c66SRichard Henderson {
276806f38c66SRichard Henderson     size_t size = addr_last - addr + 1;
276906f38c66SRichard Henderson     void *p = mmap((void *)addr, size, PROT_NONE,
277006f38c66SRichard Henderson                    MAP_ANONYMOUS | MAP_PRIVATE |
277106f38c66SRichard Henderson                    MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
277206f38c66SRichard Henderson     int ret;
277306f38c66SRichard Henderson 
277406f38c66SRichard Henderson     if (p == MAP_FAILED) {
277506f38c66SRichard Henderson         return errno == EEXIST ? 0 : -1;
277606f38c66SRichard Henderson     }
277706f38c66SRichard Henderson     ret = p == (void *)addr;
277806f38c66SRichard Henderson     if (!keep || !ret) {
277906f38c66SRichard Henderson         munmap(p, size);
278006f38c66SRichard Henderson     }
278106f38c66SRichard Henderson     return ret;
278206f38c66SRichard Henderson }
278306f38c66SRichard Henderson 
278406f38c66SRichard Henderson /**
278506f38c66SRichard Henderson  * pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t size, uintptr_t brk)
278606f38c66SRichard Henderson  * @addr: host address
278706f38c66SRichard Henderson  * @addr_last: host last address
278806f38c66SRichard Henderson  * @brk: host brk
278906f38c66SRichard Henderson  *
279006f38c66SRichard Henderson  * Like pgb_try_mmap, but additionally reserve some memory following brk.
279106f38c66SRichard Henderson  */
279206f38c66SRichard Henderson static int pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t addr_last,
279306f38c66SRichard Henderson                                  uintptr_t brk, bool keep)
279406f38c66SRichard Henderson {
279506f38c66SRichard Henderson     uintptr_t brk_last = brk + 16 * MiB - 1;
279606f38c66SRichard Henderson 
279706f38c66SRichard Henderson     /* Do not map anything close to the host brk. */
279806f38c66SRichard Henderson     if (addr <= brk_last && brk <= addr_last) {
279906f38c66SRichard Henderson         return 0;
280006f38c66SRichard Henderson     }
280106f38c66SRichard Henderson     return pgb_try_mmap(addr, addr_last, keep);
280206f38c66SRichard Henderson }
280306f38c66SRichard Henderson 
280406f38c66SRichard Henderson /**
280506f38c66SRichard Henderson  * pgb_try_mmap_set:
280606f38c66SRichard Henderson  * @ga: set of guest addrs
280706f38c66SRichard Henderson  * @base: guest_base
280806f38c66SRichard Henderson  * @brk: host brk
280906f38c66SRichard Henderson  *
281006f38c66SRichard Henderson  * Return true if all @ga can be mapped by the host at @base.
281106f38c66SRichard Henderson  * On success, retain the mapping at index 0 for reserved_va.
281206f38c66SRichard Henderson  */
281306f38c66SRichard Henderson 
281406f38c66SRichard Henderson typedef struct PGBAddrs {
281506f38c66SRichard Henderson     uintptr_t bounds[3][2]; /* start/last pairs */
281606f38c66SRichard Henderson     int nbounds;
281706f38c66SRichard Henderson } PGBAddrs;
281806f38c66SRichard Henderson 
281906f38c66SRichard Henderson static bool pgb_try_mmap_set(const PGBAddrs *ga, uintptr_t base, uintptr_t brk)
282006f38c66SRichard Henderson {
282106f38c66SRichard Henderson     for (int i = ga->nbounds - 1; i >= 0; --i) {
282206f38c66SRichard Henderson         if (pgb_try_mmap_skip_brk(ga->bounds[i][0] + base,
282306f38c66SRichard Henderson                                   ga->bounds[i][1] + base,
282406f38c66SRichard Henderson                                   brk, i == 0 && reserved_va) <= 0) {
282506f38c66SRichard Henderson             return false;
282606f38c66SRichard Henderson         }
282706f38c66SRichard Henderson     }
282806f38c66SRichard Henderson     return true;
282906f38c66SRichard Henderson }
283006f38c66SRichard Henderson 
283106f38c66SRichard Henderson /**
283206f38c66SRichard Henderson  * pgb_addr_set:
283306f38c66SRichard Henderson  * @ga: output set of guest addrs
283406f38c66SRichard Henderson  * @guest_loaddr: guest image low address
283506f38c66SRichard Henderson  * @guest_loaddr: guest image high address
283606f38c66SRichard Henderson  * @identity: create for identity mapping
283706f38c66SRichard Henderson  *
283806f38c66SRichard Henderson  * Fill in @ga with the image, COMMPAGE and NULL page.
283906f38c66SRichard Henderson  */
284006f38c66SRichard Henderson static bool pgb_addr_set(PGBAddrs *ga, abi_ulong guest_loaddr,
284106f38c66SRichard Henderson                          abi_ulong guest_hiaddr, bool try_identity)
284206f38c66SRichard Henderson {
284306f38c66SRichard Henderson     int n;
284406f38c66SRichard Henderson 
284506f38c66SRichard Henderson     /*
284606f38c66SRichard Henderson      * With a low commpage, or a guest mapped very low,
284706f38c66SRichard Henderson      * we may not be able to use the identity map.
284806f38c66SRichard Henderson      */
284906f38c66SRichard Henderson     if (try_identity) {
285006f38c66SRichard Henderson         if (LO_COMMPAGE != -1 && LO_COMMPAGE < mmap_min_addr) {
285106f38c66SRichard Henderson             return false;
285206f38c66SRichard Henderson         }
285306f38c66SRichard Henderson         if (guest_loaddr != 0 && guest_loaddr < mmap_min_addr) {
285406f38c66SRichard Henderson             return false;
285506f38c66SRichard Henderson         }
285606f38c66SRichard Henderson     }
285706f38c66SRichard Henderson 
285806f38c66SRichard Henderson     memset(ga, 0, sizeof(*ga));
285906f38c66SRichard Henderson     n = 0;
286006f38c66SRichard Henderson 
286106f38c66SRichard Henderson     if (reserved_va) {
286206f38c66SRichard Henderson         ga->bounds[n][0] = try_identity ? mmap_min_addr : 0;
286306f38c66SRichard Henderson         ga->bounds[n][1] = reserved_va;
286406f38c66SRichard Henderson         n++;
286506f38c66SRichard Henderson         /* LO_COMMPAGE and NULL handled by reserving from 0. */
286606f38c66SRichard Henderson     } else {
286706f38c66SRichard Henderson         /* Add any LO_COMMPAGE or NULL page. */
286806f38c66SRichard Henderson         if (LO_COMMPAGE != -1) {
286906f38c66SRichard Henderson             ga->bounds[n][0] = 0;
287006f38c66SRichard Henderson             ga->bounds[n][1] = LO_COMMPAGE + TARGET_PAGE_SIZE - 1;
287106f38c66SRichard Henderson             n++;
287206f38c66SRichard Henderson         } else if (!try_identity) {
287306f38c66SRichard Henderson             ga->bounds[n][0] = 0;
287406f38c66SRichard Henderson             ga->bounds[n][1] = TARGET_PAGE_SIZE - 1;
287506f38c66SRichard Henderson             n++;
287606f38c66SRichard Henderson         }
287706f38c66SRichard Henderson 
287806f38c66SRichard Henderson         /* Add the guest image for ET_EXEC. */
287906f38c66SRichard Henderson         if (guest_loaddr) {
288006f38c66SRichard Henderson             ga->bounds[n][0] = guest_loaddr;
288106f38c66SRichard Henderson             ga->bounds[n][1] = guest_hiaddr;
288206f38c66SRichard Henderson             n++;
288306f38c66SRichard Henderson         }
288406f38c66SRichard Henderson     }
288506f38c66SRichard Henderson 
288606f38c66SRichard Henderson     /*
288706f38c66SRichard Henderson      * Temporarily disable
288806f38c66SRichard Henderson      *   "comparison is always false due to limited range of data type"
288906f38c66SRichard Henderson      * due to comparison between unsigned and (possible) 0.
289006f38c66SRichard Henderson      */
289106f38c66SRichard Henderson #pragma GCC diagnostic push
289206f38c66SRichard Henderson #pragma GCC diagnostic ignored "-Wtype-limits"
289306f38c66SRichard Henderson 
289406f38c66SRichard Henderson     /* Add any HI_COMMPAGE not covered by reserved_va. */
289506f38c66SRichard Henderson     if (reserved_va < HI_COMMPAGE) {
289606f38c66SRichard Henderson         ga->bounds[n][0] = HI_COMMPAGE & qemu_host_page_mask;
289706f38c66SRichard Henderson         ga->bounds[n][1] = HI_COMMPAGE + TARGET_PAGE_SIZE - 1;
289806f38c66SRichard Henderson         n++;
289906f38c66SRichard Henderson     }
290006f38c66SRichard Henderson 
290106f38c66SRichard Henderson #pragma GCC diagnostic pop
290206f38c66SRichard Henderson 
290306f38c66SRichard Henderson     ga->nbounds = n;
290406f38c66SRichard Henderson     return true;
290506f38c66SRichard Henderson }
290606f38c66SRichard Henderson 
2907ee947430SAlex Bennée static void pgb_fail_in_use(const char *image_name)
2908ee947430SAlex Bennée {
2909ee947430SAlex Bennée     error_report("%s: requires virtual address space that is in use "
2910ee947430SAlex Bennée                  "(omit the -B option or choose a different value)",
2911ee947430SAlex Bennée                  image_name);
2912ee947430SAlex Bennée     exit(EXIT_FAILURE);
2913ee947430SAlex Bennée }
2914ee947430SAlex Bennée 
291506f38c66SRichard Henderson static void pgb_fixed(const char *image_name, uintptr_t guest_loaddr,
291606f38c66SRichard Henderson                       uintptr_t guest_hiaddr, uintptr_t align)
2917ee947430SAlex Bennée {
291806f38c66SRichard Henderson     PGBAddrs ga;
291906f38c66SRichard Henderson     uintptr_t brk = (uintptr_t)sbrk(0);
2920ee947430SAlex Bennée 
2921ee947430SAlex Bennée     if (!QEMU_IS_ALIGNED(guest_base, align)) {
29225ca870b9SRichard Henderson         fprintf(stderr, "Requested guest base %p does not satisfy "
292306f38c66SRichard Henderson                 "host minimum alignment (0x%" PRIxPTR ")\n",
29245ca870b9SRichard Henderson                 (void *)guest_base, align);
2925ee947430SAlex Bennée         exit(EXIT_FAILURE);
2926ee947430SAlex Bennée     }
2927ee947430SAlex Bennée 
292806f38c66SRichard Henderson     if (!pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, !guest_base)
292906f38c66SRichard Henderson         || !pgb_try_mmap_set(&ga, guest_base, brk)) {
2930ee947430SAlex Bennée         pgb_fail_in_use(image_name);
2931ee947430SAlex Bennée     }
2932ee947430SAlex Bennée }
2933ee947430SAlex Bennée 
2934ad592e37SAlex Bennée /**
2935dd558855SRichard Henderson  * pgb_find_fallback:
2936ad592e37SAlex Bennée  *
2937dd558855SRichard Henderson  * This is a fallback method for finding holes in the host address space
2938dd558855SRichard Henderson  * if we don't have the benefit of being able to access /proc/self/map.
2939dd558855SRichard Henderson  * It can potentially take a very long time as we can only dumbly iterate
2940dd558855SRichard Henderson  * up the host address space seeing if the allocation would work.
2941ad592e37SAlex Bennée  */
2942dd558855SRichard Henderson static uintptr_t pgb_find_fallback(const PGBAddrs *ga, uintptr_t align,
2943dd558855SRichard Henderson                                    uintptr_t brk)
2944ad592e37SAlex Bennée {
2945dd558855SRichard Henderson     /* TODO: come up with a better estimate of how much to skip. */
2946dd558855SRichard Henderson     uintptr_t skip = sizeof(uintptr_t) == 4 ? MiB : GiB;
2947ad592e37SAlex Bennée 
2948dd558855SRichard Henderson     for (uintptr_t base = skip; ; base += skip) {
2949dd558855SRichard Henderson         base = ROUND_UP(base, align);
2950dd558855SRichard Henderson         if (pgb_try_mmap_set(ga, base, brk)) {
2951dd558855SRichard Henderson             return base;
2952dd558855SRichard Henderson         }
2953dd558855SRichard Henderson         if (base >= -skip) {
2954dd558855SRichard Henderson             return -1;
2955dd558855SRichard Henderson         }
2956dd558855SRichard Henderson     }
2957dd558855SRichard Henderson }
2958dd558855SRichard Henderson 
2959dd558855SRichard Henderson static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base,
2960dd558855SRichard Henderson                                IntervalTreeRoot *root)
2961dd558855SRichard Henderson {
2962dd558855SRichard Henderson     for (int i = ga->nbounds - 1; i >= 0; --i) {
2963dd558855SRichard Henderson         uintptr_t s = base + ga->bounds[i][0];
2964dd558855SRichard Henderson         uintptr_t l = base + ga->bounds[i][1];
2965dd558855SRichard Henderson         IntervalTreeNode *n;
2966dd558855SRichard Henderson 
2967dd558855SRichard Henderson         if (l < s) {
2968dd558855SRichard Henderson             /* Wraparound. Skip to advance S to mmap_min_addr. */
2969dd558855SRichard Henderson             return mmap_min_addr - s;
2970dd558855SRichard Henderson         }
2971dd558855SRichard Henderson 
2972dd558855SRichard Henderson         n = interval_tree_iter_first(root, s, l);
2973dd558855SRichard Henderson         if (n != NULL) {
2974dd558855SRichard Henderson             /* Conflict.  Skip to advance S to LAST + 1. */
2975dd558855SRichard Henderson             return n->last - s + 1;
2976dd558855SRichard Henderson         }
2977dd558855SRichard Henderson     }
2978dd558855SRichard Henderson     return 0;  /* success */
2979dd558855SRichard Henderson }
2980dd558855SRichard Henderson 
2981dd558855SRichard Henderson static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root,
2982dd558855SRichard Henderson                                 uintptr_t align, uintptr_t brk)
2983dd558855SRichard Henderson {
2984dd558855SRichard Henderson     uintptr_t last = mmap_min_addr;
2985dd558855SRichard Henderson     uintptr_t base, skip;
2986ad592e37SAlex Bennée 
2987ad592e37SAlex Bennée     while (true) {
2988dd558855SRichard Henderson         base = ROUND_UP(last, align);
2989dd558855SRichard Henderson         if (base < last) {
2990ad592e37SAlex Bennée             return -1;
2991ad592e37SAlex Bennée         }
2992dd558855SRichard Henderson 
2993dd558855SRichard Henderson         skip = pgb_try_itree(ga, base, root);
2994dd558855SRichard Henderson         if (skip == 0) {
2995dd558855SRichard Henderson             break;
29962667e069SAlex Bennée         }
2997dd558855SRichard Henderson 
2998dd558855SRichard Henderson         last = base + skip;
2999dd558855SRichard Henderson         if (last < base) {
3000dd558855SRichard Henderson             return -1;
3001ad592e37SAlex Bennée         }
3002ad592e37SAlex Bennée     }
3003ad592e37SAlex Bennée 
3004dd558855SRichard Henderson     /*
3005dd558855SRichard Henderson      * We've chosen 'base' based on holes in the interval tree,
3006dd558855SRichard Henderson      * but we don't yet know if it is a valid host address.
3007dd558855SRichard Henderson      * Because it is the first matching hole, if the host addresses
3008dd558855SRichard Henderson      * are invalid we know there are no further matches.
3009dd558855SRichard Henderson      */
3010dd558855SRichard Henderson     return pgb_try_mmap_set(ga, base, brk) ? base : -1;
3011dd558855SRichard Henderson }
3012dd558855SRichard Henderson 
3013dd558855SRichard Henderson static void pgb_dynamic(const char *image_name, uintptr_t guest_loaddr,
3014dd558855SRichard Henderson                         uintptr_t guest_hiaddr, uintptr_t align)
3015ee947430SAlex Bennée {
3016dd558855SRichard Henderson     IntervalTreeRoot *root;
3017dd558855SRichard Henderson     uintptr_t brk, ret;
3018dd558855SRichard Henderson     PGBAddrs ga;
3019ee947430SAlex Bennée 
3020ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_loaddr, align));
3021ee947430SAlex Bennée 
3022dd558855SRichard Henderson     /* Try the identity map first. */
3023dd558855SRichard Henderson     if (pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, true)) {
3024dd558855SRichard Henderson         brk = (uintptr_t)sbrk(0);
3025dd558855SRichard Henderson         if (pgb_try_mmap_set(&ga, 0, brk)) {
3026dd558855SRichard Henderson             guest_base = 0;
3027dd558855SRichard Henderson             return;
3028dd558855SRichard Henderson         }
3029dd558855SRichard Henderson     }
3030dd558855SRichard Henderson 
3031dd558855SRichard Henderson     /*
3032dd558855SRichard Henderson      * Rebuild the address set for non-identity map.
3033dd558855SRichard Henderson      * This differs in the mapping of the guest NULL page.
3034dd558855SRichard Henderson      */
3035dd558855SRichard Henderson     pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, false);
3036dd558855SRichard Henderson 
3037dd558855SRichard Henderson     root = read_self_maps();
3038ee947430SAlex Bennée 
3039ee947430SAlex Bennée     /* Read brk after we've read the maps, which will malloc. */
3040ee947430SAlex Bennée     brk = (uintptr_t)sbrk(0);
3041ee947430SAlex Bennée 
3042dd558855SRichard Henderson     if (!root) {
3043dd558855SRichard Henderson         ret = pgb_find_fallback(&ga, align, brk);
3044ee947430SAlex Bennée     } else {
3045ee947430SAlex Bennée         /*
3046dd558855SRichard Henderson          * Reserve the area close to the host brk.
3047dd558855SRichard Henderson          * This will be freed with the rest of the tree.
3048ee947430SAlex Bennée          */
3049dd558855SRichard Henderson         IntervalTreeNode *b = g_new0(IntervalTreeNode, 1);
3050dd558855SRichard Henderson         b->start = brk;
3051dd558855SRichard Henderson         b->last = brk + 16 * MiB - 1;
3052dd558855SRichard Henderson         interval_tree_insert(b, root);
3053dd558855SRichard Henderson 
3054dd558855SRichard Henderson         ret = pgb_find_itree(&ga, root, align, brk);
3055dd558855SRichard Henderson         free_self_maps(root);
3056ee947430SAlex Bennée     }
3057ee947430SAlex Bennée 
3058dd558855SRichard Henderson     if (ret == -1) {
3059dd558855SRichard Henderson         int w = TARGET_LONG_BITS / 4;
3060dd558855SRichard Henderson 
3061dd558855SRichard Henderson         error_report("%s: Unable to find a guest_base to satisfy all "
3062dd558855SRichard Henderson                      "guest address mapping requirements", image_name);
3063dd558855SRichard Henderson 
3064dd558855SRichard Henderson         for (int i = 0; i < ga.nbounds; ++i) {
3065dd558855SRichard Henderson             error_printf("  %0*" PRIx64 "-%0*" PRIx64 "\n",
3066dd558855SRichard Henderson                          w, (uint64_t)ga.bounds[i][0],
3067dd558855SRichard Henderson                          w, (uint64_t)ga.bounds[i][1]);
3068dd558855SRichard Henderson         }
3069ee947430SAlex Bennée         exit(EXIT_FAILURE);
3070ee947430SAlex Bennée     }
3071dd558855SRichard Henderson     guest_base = ret;
3072ee947430SAlex Bennée }
3073ee947430SAlex Bennée 
3074ee947430SAlex Bennée void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
3075ee947430SAlex Bennée                       abi_ulong guest_hiaddr)
3076dce10401SMeador Inge {
307730ab9ef2SRichard Henderson     /* In order to use host shmat, we must be able to honor SHMLBA.  */
3078ee947430SAlex Bennée     uintptr_t align = MAX(SHMLBA, qemu_host_page_size);
3079dce10401SMeador Inge 
30800c441aebSRichard Henderson     /* Sanity check the guest binary. */
30810c441aebSRichard Henderson     if (reserved_va) {
30820c441aebSRichard Henderson         if (guest_hiaddr > reserved_va) {
30830c441aebSRichard Henderson             error_report("%s: requires more than reserved virtual "
30840c441aebSRichard Henderson                          "address space (0x%" PRIx64 " > 0x%lx)",
30850c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr, reserved_va);
30860c441aebSRichard Henderson             exit(EXIT_FAILURE);
30870c441aebSRichard Henderson         }
30880c441aebSRichard Henderson     } else {
30890c441aebSRichard Henderson         if (guest_hiaddr != (uintptr_t)guest_hiaddr) {
30900c441aebSRichard Henderson             error_report("%s: requires more virtual address space "
30910c441aebSRichard Henderson                          "than the host can provide (0x%" PRIx64 ")",
30920c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr + 1);
30930c441aebSRichard Henderson             exit(EXIT_FAILURE);
30940c441aebSRichard Henderson         }
30950c441aebSRichard Henderson     }
30960c441aebSRichard Henderson 
3097ee947430SAlex Bennée     if (have_guest_base) {
309806f38c66SRichard Henderson         pgb_fixed(image_name, guest_loaddr, guest_hiaddr, align);
3099293f2060SLuke Shumaker     } else {
3100dd558855SRichard Henderson         pgb_dynamic(image_name, guest_loaddr, guest_hiaddr, align);
3101806d1021SMeador Inge     }
3102806d1021SMeador Inge 
3103ee947430SAlex Bennée     /* Reserve and initialize the commpage. */
3104ee947430SAlex Bennée     if (!init_guest_commpage()) {
310506f38c66SRichard Henderson         /* We have already probed for the commpage being free. */
310606f38c66SRichard Henderson         g_assert_not_reached();
3107dce10401SMeador Inge     }
3108dce10401SMeador Inge 
3109ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_base, align));
3110ee947430SAlex Bennée     qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space "
3111ee947430SAlex Bennée                   "@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
3112dce10401SMeador Inge }
3113dce10401SMeador Inge 
311483f990ebSRichard Henderson enum {
311583f990ebSRichard Henderson     /* The string "GNU\0" as a magic number. */
311683f990ebSRichard Henderson     GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
311783f990ebSRichard Henderson     NOTE_DATA_SZ = 1 * KiB,
311883f990ebSRichard Henderson     NOTE_NAME_SZ = 4,
311983f990ebSRichard Henderson     ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
312083f990ebSRichard Henderson };
312183f990ebSRichard Henderson 
312283f990ebSRichard Henderson /*
312383f990ebSRichard Henderson  * Process a single gnu_property entry.
312483f990ebSRichard Henderson  * Return false for error.
312583f990ebSRichard Henderson  */
312683f990ebSRichard Henderson static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
312783f990ebSRichard Henderson                                struct image_info *info, bool have_prev_type,
312883f990ebSRichard Henderson                                uint32_t *prev_type, Error **errp)
312983f990ebSRichard Henderson {
313083f990ebSRichard Henderson     uint32_t pr_type, pr_datasz, step;
313183f990ebSRichard Henderson 
313283f990ebSRichard Henderson     if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
313383f990ebSRichard Henderson         goto error_data;
313483f990ebSRichard Henderson     }
313583f990ebSRichard Henderson     datasz -= *off;
313683f990ebSRichard Henderson     data += *off / sizeof(uint32_t);
313783f990ebSRichard Henderson 
313883f990ebSRichard Henderson     if (datasz < 2 * sizeof(uint32_t)) {
313983f990ebSRichard Henderson         goto error_data;
314083f990ebSRichard Henderson     }
314183f990ebSRichard Henderson     pr_type = data[0];
314283f990ebSRichard Henderson     pr_datasz = data[1];
314383f990ebSRichard Henderson     data += 2;
314483f990ebSRichard Henderson     datasz -= 2 * sizeof(uint32_t);
314583f990ebSRichard Henderson     step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
314683f990ebSRichard Henderson     if (step > datasz) {
314783f990ebSRichard Henderson         goto error_data;
314883f990ebSRichard Henderson     }
314983f990ebSRichard Henderson 
315083f990ebSRichard Henderson     /* Properties are supposed to be unique and sorted on pr_type. */
315183f990ebSRichard Henderson     if (have_prev_type && pr_type <= *prev_type) {
315283f990ebSRichard Henderson         if (pr_type == *prev_type) {
315383f990ebSRichard Henderson             error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
315483f990ebSRichard Henderson         } else {
315583f990ebSRichard Henderson             error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
315683f990ebSRichard Henderson         }
315783f990ebSRichard Henderson         return false;
315883f990ebSRichard Henderson     }
315983f990ebSRichard Henderson     *prev_type = pr_type;
316083f990ebSRichard Henderson 
316183f990ebSRichard Henderson     if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
316283f990ebSRichard Henderson         return false;
316383f990ebSRichard Henderson     }
316483f990ebSRichard Henderson 
316583f990ebSRichard Henderson     *off += 2 * sizeof(uint32_t) + step;
316683f990ebSRichard Henderson     return true;
316783f990ebSRichard Henderson 
316883f990ebSRichard Henderson  error_data:
316983f990ebSRichard Henderson     error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
317083f990ebSRichard Henderson     return false;
317183f990ebSRichard Henderson }
317283f990ebSRichard Henderson 
317383f990ebSRichard Henderson /* Process NT_GNU_PROPERTY_TYPE_0. */
31743bd02386SRichard Henderson static bool parse_elf_properties(const ImageSource *src,
317583f990ebSRichard Henderson                                  struct image_info *info,
317683f990ebSRichard Henderson                                  const struct elf_phdr *phdr,
317783f990ebSRichard Henderson                                  Error **errp)
317883f990ebSRichard Henderson {
317983f990ebSRichard Henderson     union {
318083f990ebSRichard Henderson         struct elf_note nhdr;
318183f990ebSRichard Henderson         uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
318283f990ebSRichard Henderson     } note;
318383f990ebSRichard Henderson 
318483f990ebSRichard Henderson     int n, off, datasz;
318583f990ebSRichard Henderson     bool have_prev_type;
318683f990ebSRichard Henderson     uint32_t prev_type;
318783f990ebSRichard Henderson 
318883f990ebSRichard Henderson     /* Unless the arch requires properties, ignore them. */
318983f990ebSRichard Henderson     if (!ARCH_USE_GNU_PROPERTY) {
319083f990ebSRichard Henderson         return true;
319183f990ebSRichard Henderson     }
319283f990ebSRichard Henderson 
319383f990ebSRichard Henderson     /* If the properties are crazy large, that's too bad. */
319483f990ebSRichard Henderson     n = phdr->p_filesz;
319583f990ebSRichard Henderson     if (n > sizeof(note)) {
319683f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too large");
319783f990ebSRichard Henderson         return false;
319883f990ebSRichard Henderson     }
319983f990ebSRichard Henderson     if (n < sizeof(note.nhdr)) {
320083f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too small");
320183f990ebSRichard Henderson         return false;
320283f990ebSRichard Henderson     }
320383f990ebSRichard Henderson 
32043bd02386SRichard Henderson     if (!imgsrc_read(&note, phdr->p_offset, n, src, errp)) {
320583f990ebSRichard Henderson         return false;
320683f990ebSRichard Henderson     }
320783f990ebSRichard Henderson 
320883f990ebSRichard Henderson     /*
320983f990ebSRichard Henderson      * The contents of a valid PT_GNU_PROPERTY is a sequence
321083f990ebSRichard Henderson      * of uint32_t -- swap them all now.
321183f990ebSRichard Henderson      */
321283f990ebSRichard Henderson #ifdef BSWAP_NEEDED
321383f990ebSRichard Henderson     for (int i = 0; i < n / 4; i++) {
321483f990ebSRichard Henderson         bswap32s(note.data + i);
321583f990ebSRichard Henderson     }
321683f990ebSRichard Henderson #endif
321783f990ebSRichard Henderson 
321883f990ebSRichard Henderson     /*
321983f990ebSRichard Henderson      * Note that nhdr is 3 words, and that the "name" described by namesz
322083f990ebSRichard Henderson      * immediately follows nhdr and is thus at the 4th word.  Further, all
322183f990ebSRichard Henderson      * of the inputs to the kernel's round_up are multiples of 4.
322283f990ebSRichard Henderson      */
322383f990ebSRichard Henderson     if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
322483f990ebSRichard Henderson         note.nhdr.n_namesz != NOTE_NAME_SZ ||
322583f990ebSRichard Henderson         note.data[3] != GNU0_MAGIC) {
322683f990ebSRichard Henderson         error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
322783f990ebSRichard Henderson         return false;
322883f990ebSRichard Henderson     }
322983f990ebSRichard Henderson     off = sizeof(note.nhdr) + NOTE_NAME_SZ;
323083f990ebSRichard Henderson 
323183f990ebSRichard Henderson     datasz = note.nhdr.n_descsz + off;
323283f990ebSRichard Henderson     if (datasz > n) {
323383f990ebSRichard Henderson         error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
323483f990ebSRichard Henderson         return false;
323583f990ebSRichard Henderson     }
323683f990ebSRichard Henderson 
323783f990ebSRichard Henderson     have_prev_type = false;
323883f990ebSRichard Henderson     prev_type = 0;
323983f990ebSRichard Henderson     while (1) {
324083f990ebSRichard Henderson         if (off == datasz) {
324183f990ebSRichard Henderson             return true;  /* end, exit ok */
324283f990ebSRichard Henderson         }
324383f990ebSRichard Henderson         if (!parse_elf_property(note.data, &off, datasz, info,
324483f990ebSRichard Henderson                                 have_prev_type, &prev_type, errp)) {
324583f990ebSRichard Henderson             return false;
324683f990ebSRichard Henderson         }
324783f990ebSRichard Henderson         have_prev_type = true;
324883f990ebSRichard Henderson     }
324983f990ebSRichard Henderson }
325083f990ebSRichard Henderson 
32513bd02386SRichard Henderson /**
32523bd02386SRichard Henderson  * load_elf_image: Load an ELF image into the address space.
32533bd02386SRichard Henderson  * @image_name: the filename of the image, to use in error messages.
32543bd02386SRichard Henderson  * @src: the ImageSource from which to read.
32553bd02386SRichard Henderson  * @info: info collected from the loaded image.
32563bd02386SRichard Henderson  * @ehdr: the ELF header, not yet bswapped.
32573bd02386SRichard Henderson  * @pinterp_name: record any PT_INTERP string found.
32583bd02386SRichard Henderson  *
32593bd02386SRichard Henderson  * On return: @info values will be filled in, as necessary or available.
32603bd02386SRichard Henderson  */
326131e31b8aSbellard 
32623bd02386SRichard Henderson static void load_elf_image(const char *image_name, const ImageSource *src,
326340d487eeSRichard Henderson                            struct image_info *info, struct elfhdr *ehdr,
32643bd02386SRichard Henderson                            char **pinterp_name)
326531e31b8aSbellard {
32663bd02386SRichard Henderson     g_autofree struct elf_phdr *phdr = NULL;
32678e62a717SRichard Henderson     abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
32683bd02386SRichard Henderson     int i, prot_exec;
3269c7f17e7bSRichard Henderson     Error *err = NULL;
327031e31b8aSbellard 
32713bd02386SRichard Henderson     /*
32723bd02386SRichard Henderson      * First of all, some simple consistency checks.
32733bd02386SRichard Henderson      * Note that we rely on the bswapped ehdr staying in bprm_buf,
32743bd02386SRichard Henderson      * for later use by load_elf_binary and create_elf_tables.
32753bd02386SRichard Henderson      */
32763bd02386SRichard Henderson     if (!imgsrc_read(ehdr, 0, sizeof(*ehdr), src, &err)) {
32773bd02386SRichard Henderson         goto exit_errmsg;
32783bd02386SRichard Henderson     }
32798e62a717SRichard Henderson     if (!elf_check_ident(ehdr)) {
3280c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
32818e62a717SRichard Henderson         goto exit_errmsg;
32828e62a717SRichard Henderson     }
32838e62a717SRichard Henderson     bswap_ehdr(ehdr);
32848e62a717SRichard Henderson     if (!elf_check_ehdr(ehdr)) {
3285c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
32868e62a717SRichard Henderson         goto exit_errmsg;
328731e31b8aSbellard     }
328831e31b8aSbellard 
32893bd02386SRichard Henderson     phdr = imgsrc_read_alloc(ehdr->e_phoff,
32903bd02386SRichard Henderson                              ehdr->e_phnum * sizeof(struct elf_phdr),
32913bd02386SRichard Henderson                              src, &err);
32923bd02386SRichard Henderson     if (phdr == NULL) {
32933bd02386SRichard Henderson         goto exit_errmsg;
329431e31b8aSbellard     }
32958e62a717SRichard Henderson     bswap_phdr(phdr, ehdr->e_phnum);
329609bfb054Sbellard 
32971af02e83SMike Frysinger     info->nsegs = 0;
32981af02e83SMike Frysinger     info->pt_dynamic_addr = 0;
32991af02e83SMike Frysinger 
330098c1076cSAlex Bennée     mmap_lock();
330198c1076cSAlex Bennée 
33028a1a5274SRichard Henderson     /*
33038a1a5274SRichard Henderson      * Find the maximum size of the image and allocate an appropriate
33048a1a5274SRichard Henderson      * amount of memory to handle that.  Locate the interpreter, if any.
33058a1a5274SRichard Henderson      */
3306682674b8SRichard Henderson     loaddr = -1, hiaddr = 0;
330733143c44SLaurent Vivier     info->alignment = 0;
3308872f3d04SRichard Henderson     info->exec_stack = EXSTACK_DEFAULT;
33098e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; ++i) {
33104d9d535aSRichard Henderson         struct elf_phdr *eppnt = phdr + i;
33114d9d535aSRichard Henderson         if (eppnt->p_type == PT_LOAD) {
331282d70a84SRichard Henderson             abi_ulong a = eppnt->p_vaddr & TARGET_PAGE_MASK;
3313682674b8SRichard Henderson             if (a < loaddr) {
3314682674b8SRichard Henderson                 loaddr = a;
3315682674b8SRichard Henderson             }
3316a3a67f54SRichard Henderson             a = eppnt->p_vaddr + eppnt->p_memsz - 1;
3317682674b8SRichard Henderson             if (a > hiaddr) {
3318682674b8SRichard Henderson                 hiaddr = a;
3319682674b8SRichard Henderson             }
33201af02e83SMike Frysinger             ++info->nsegs;
33214d9d535aSRichard Henderson             info->alignment |= eppnt->p_align;
33228a1a5274SRichard Henderson         } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
33238a1a5274SRichard Henderson             g_autofree char *interp_name = NULL;
33248a1a5274SRichard Henderson 
33258a1a5274SRichard Henderson             if (*pinterp_name) {
3326c7f17e7bSRichard Henderson                 error_setg(&err, "Multiple PT_INTERP entries");
33278a1a5274SRichard Henderson                 goto exit_errmsg;
33288a1a5274SRichard Henderson             }
3329c7f17e7bSRichard Henderson 
33303bd02386SRichard Henderson             interp_name = imgsrc_read_alloc(eppnt->p_offset, eppnt->p_filesz,
33313bd02386SRichard Henderson                                             src, &err);
33323bd02386SRichard Henderson             if (interp_name == NULL) {
33333bd02386SRichard Henderson                 goto exit_errmsg;
33348a1a5274SRichard Henderson             }
33358a1a5274SRichard Henderson             if (interp_name[eppnt->p_filesz - 1] != 0) {
3336c7f17e7bSRichard Henderson                 error_setg(&err, "Invalid PT_INTERP entry");
33378a1a5274SRichard Henderson                 goto exit_errmsg;
33388a1a5274SRichard Henderson             }
33398a1a5274SRichard Henderson             *pinterp_name = g_steal_pointer(&interp_name);
334083f990ebSRichard Henderson         } else if (eppnt->p_type == PT_GNU_PROPERTY) {
33413bd02386SRichard Henderson             if (!parse_elf_properties(src, info, eppnt, &err)) {
334283f990ebSRichard Henderson                 goto exit_errmsg;
334383f990ebSRichard Henderson             }
3344872f3d04SRichard Henderson         } else if (eppnt->p_type == PT_GNU_STACK) {
3345872f3d04SRichard Henderson             info->exec_stack = eppnt->p_flags & PF_X;
3346682674b8SRichard Henderson         }
3347682674b8SRichard Henderson     }
3348682674b8SRichard Henderson 
33491ea06dedSRichard Henderson     load_addr = loaddr;
33501ea06dedSRichard Henderson 
33516fd59449SRichard Henderson     if (pinterp_name != NULL) {
33526fd59449SRichard Henderson         if (ehdr->e_type == ET_EXEC) {
33536fd59449SRichard Henderson             /*
33546fd59449SRichard Henderson              * Make sure that the low address does not conflict with
33556fd59449SRichard Henderson              * MMAP_MIN_ADDR or the QEMU application itself.
33566fd59449SRichard Henderson              */
33576fd59449SRichard Henderson             probe_guest_base(image_name, loaddr, hiaddr);
3358ee947430SAlex Bennée         } else {
33591ea06dedSRichard Henderson             abi_ulong align;
33601ea06dedSRichard Henderson 
3361ee947430SAlex Bennée             /*
3362ee947430SAlex Bennée              * The binary is dynamic, but we still need to
3363ee947430SAlex Bennée              * select guest_base.  In this case we pass a size.
3364ee947430SAlex Bennée              */
3365ee947430SAlex Bennée             probe_guest_base(image_name, 0, hiaddr - loaddr);
33661ea06dedSRichard Henderson 
33671ea06dedSRichard Henderson             /*
33681ea06dedSRichard Henderson              * Avoid collision with the loader by providing a different
33691ea06dedSRichard Henderson              * default load address.
33701ea06dedSRichard Henderson              */
33711ea06dedSRichard Henderson             load_addr += elf_et_dyn_base;
33721ea06dedSRichard Henderson 
33731ea06dedSRichard Henderson             /*
33741ea06dedSRichard Henderson              * TODO: Better support for mmap alignment is desirable.
33751ea06dedSRichard Henderson              * Since we do not have complete control over the guest
33761ea06dedSRichard Henderson              * address space, we prefer the kernel to choose some address
33771ea06dedSRichard Henderson              * rather than force the use of LOAD_ADDR via MAP_FIXED.
33781ea06dedSRichard Henderson              * But without MAP_FIXED we cannot guarantee alignment,
33791ea06dedSRichard Henderson              * only suggest it.
33801ea06dedSRichard Henderson              */
33811ea06dedSRichard Henderson             align = pow2ceil(info->alignment);
33821ea06dedSRichard Henderson             if (align) {
33831ea06dedSRichard Henderson                 load_addr &= -align;
33841ea06dedSRichard Henderson             }
33856fd59449SRichard Henderson         }
33866fd59449SRichard Henderson     }
33876fd59449SRichard Henderson 
33886fd59449SRichard Henderson     /*
33896fd59449SRichard Henderson      * Reserve address space for all of this.
33906fd59449SRichard Henderson      *
3391ad25051bSRichard Henderson      * In the case of ET_EXEC, we supply MAP_FIXED_NOREPLACE so that we get
3392ad25051bSRichard Henderson      * exactly the address range that is required.  Without reserved_va,
3393ad25051bSRichard Henderson      * the guest address space is not isolated.  We have attempted to avoid
3394ad25051bSRichard Henderson      * conflict with the host program itself via probe_guest_base, but using
3395ad25051bSRichard Henderson      * MAP_FIXED_NOREPLACE instead of MAP_FIXED provides an extra check.
33966fd59449SRichard Henderson      *
33976fd59449SRichard Henderson      * Otherwise this is ET_DYN, and we are searching for a location
33986fd59449SRichard Henderson      * that can hold the memory space required.  If the image is
33991ea06dedSRichard Henderson      * pre-linked, LOAD_ADDR will be non-zero, and the kernel should
34006fd59449SRichard Henderson      * honor that address if it happens to be free.
34016fd59449SRichard Henderson      *
34026fd59449SRichard Henderson      * In both cases, we will overwrite pages in this range with mappings
34036fd59449SRichard Henderson      * from the executable.
34046fd59449SRichard Henderson      */
34051ea06dedSRichard Henderson     load_addr = target_mmap(load_addr, (size_t)hiaddr - loaddr + 1, PROT_NONE,
34066fd59449SRichard Henderson                             MAP_PRIVATE | MAP_ANON | MAP_NORESERVE |
3407ad25051bSRichard Henderson                             (ehdr->e_type == ET_EXEC ? MAP_FIXED_NOREPLACE : 0),
340809bfb054Sbellard                             -1, 0);
3409682674b8SRichard Henderson     if (load_addr == -1) {
3410c7f17e7bSRichard Henderson         goto exit_mmap;
341109bfb054Sbellard     }
3412682674b8SRichard Henderson     load_bias = load_addr - loaddr;
341309bfb054Sbellard 
3414a99856cdSChristophe Lyon     if (elf_is_fdpic(ehdr)) {
34151af02e83SMike Frysinger         struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
34167267c094SAnthony Liguori             g_malloc(sizeof(*loadsegs) * info->nsegs);
34171af02e83SMike Frysinger 
34181af02e83SMike Frysinger         for (i = 0; i < ehdr->e_phnum; ++i) {
34191af02e83SMike Frysinger             switch (phdr[i].p_type) {
34201af02e83SMike Frysinger             case PT_DYNAMIC:
34211af02e83SMike Frysinger                 info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
34221af02e83SMike Frysinger                 break;
34231af02e83SMike Frysinger             case PT_LOAD:
34241af02e83SMike Frysinger                 loadsegs->addr = phdr[i].p_vaddr + load_bias;
34251af02e83SMike Frysinger                 loadsegs->p_vaddr = phdr[i].p_vaddr;
34261af02e83SMike Frysinger                 loadsegs->p_memsz = phdr[i].p_memsz;
34271af02e83SMike Frysinger                 ++loadsegs;
34281af02e83SMike Frysinger                 break;
34291af02e83SMike Frysinger             }
34301af02e83SMike Frysinger         }
34311af02e83SMike Frysinger     }
34321af02e83SMike Frysinger 
34338e62a717SRichard Henderson     info->load_bias = load_bias;
3434dc12567aSJosh Kunz     info->code_offset = load_bias;
3435dc12567aSJosh Kunz     info->data_offset = load_bias;
34368e62a717SRichard Henderson     info->load_addr = load_addr;
34378e62a717SRichard Henderson     info->entry = ehdr->e_entry + load_bias;
34388e62a717SRichard Henderson     info->start_code = -1;
34398e62a717SRichard Henderson     info->end_code = 0;
34408e62a717SRichard Henderson     info->start_data = -1;
34418e62a717SRichard Henderson     info->end_data = 0;
34421f356e8cSHelge Deller     /* Usual start for brk is after all sections of the main executable. */
3443aec338d6SRichard Henderson     info->brk = TARGET_PAGE_ALIGN(hiaddr + load_bias);
3444d8fd2954SPaul Brook     info->elf_flags = ehdr->e_flags;
34458e62a717SRichard Henderson 
3446e8384b37SRichard Henderson     prot_exec = PROT_EXEC;
3447e8384b37SRichard Henderson #ifdef TARGET_AARCH64
3448e8384b37SRichard Henderson     /*
3449e8384b37SRichard Henderson      * If the BTI feature is present, this indicates that the executable
3450e8384b37SRichard Henderson      * pages of the startup binary should be mapped with PROT_BTI, so that
3451e8384b37SRichard Henderson      * branch targets are enforced.
3452e8384b37SRichard Henderson      *
3453e8384b37SRichard Henderson      * The startup binary is either the interpreter or the static executable.
3454e8384b37SRichard Henderson      * The interpreter is responsible for all pages of a dynamic executable.
3455e8384b37SRichard Henderson      *
3456e8384b37SRichard Henderson      * Elf notes are backward compatible to older cpus.
3457e8384b37SRichard Henderson      * Do not enable BTI unless it is supported.
3458e8384b37SRichard Henderson      */
3459e8384b37SRichard Henderson     if ((info->note_flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
3460e8384b37SRichard Henderson         && (pinterp_name == NULL || *pinterp_name == 0)
3461e8384b37SRichard Henderson         && cpu_isar_feature(aa64_bti, ARM_CPU(thread_cpu))) {
3462e8384b37SRichard Henderson         prot_exec |= TARGET_PROT_BTI;
3463e8384b37SRichard Henderson     }
3464e8384b37SRichard Henderson #endif
3465e8384b37SRichard Henderson 
34668e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; i++) {
34678e62a717SRichard Henderson         struct elf_phdr *eppnt = phdr + i;
346831e31b8aSbellard         if (eppnt->p_type == PT_LOAD) {
34695f4e5b34SRichard Henderson             abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
347031e31b8aSbellard             int elf_prot = 0;
347131e31b8aSbellard 
3472e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_R) {
3473e5eaf570SRichard Henderson                 elf_prot |= PROT_READ;
3474e5eaf570SRichard Henderson             }
3475e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_W) {
3476e5eaf570SRichard Henderson                 elf_prot |= PROT_WRITE;
3477e5eaf570SRichard Henderson             }
3478e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_X) {
3479e8384b37SRichard Henderson                 elf_prot |= prot_exec;
3480e5eaf570SRichard Henderson             }
348131e31b8aSbellard 
3482682674b8SRichard Henderson             vaddr = load_bias + eppnt->p_vaddr;
3483e3d97d5cSRichard Henderson             vaddr_po = vaddr & ~TARGET_PAGE_MASK;
3484e3d97d5cSRichard Henderson             vaddr_ps = vaddr & TARGET_PAGE_MASK;
348522d113b5SGiuseppe Musacchio 
348622d113b5SGiuseppe Musacchio             vaddr_ef = vaddr + eppnt->p_filesz;
348722d113b5SGiuseppe Musacchio             vaddr_em = vaddr + eppnt->p_memsz;
3488682674b8SRichard Henderson 
3489d87146bcSGiuseppe Musacchio             /*
349022d113b5SGiuseppe Musacchio              * Some segments may be completely empty, with a non-zero p_memsz
349122d113b5SGiuseppe Musacchio              * but no backing file segment.
3492d87146bcSGiuseppe Musacchio              */
3493d87146bcSGiuseppe Musacchio             if (eppnt->p_filesz != 0) {
34943bd02386SRichard Henderson                 error = imgsrc_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
34955f4e5b34SRichard Henderson                                     elf_prot, MAP_PRIVATE | MAP_FIXED,
34963bd02386SRichard Henderson                                     src, eppnt->p_offset - vaddr_po);
3497e89f07d3Spbrook                 if (error == -1) {
3498c7f17e7bSRichard Henderson                     goto exit_mmap;
349931e31b8aSbellard                 }
35005f4e5b34SRichard Henderson             }
350131e31b8aSbellard 
35025f4e5b34SRichard Henderson             /* If the load segment requests extra zeros (e.g. bss), map it. */
35035f4e5b34SRichard Henderson             if (vaddr_ef < vaddr_em &&
3504e6e66b03SRichard Henderson                 !zero_bss(vaddr_ef, vaddr_em, elf_prot, &err)) {
3505e6e66b03SRichard Henderson                 goto exit_errmsg;
3506682674b8SRichard Henderson             }
35078e62a717SRichard Henderson 
35088e62a717SRichard Henderson             /* Find the full program boundaries.  */
35098e62a717SRichard Henderson             if (elf_prot & PROT_EXEC) {
35108e62a717SRichard Henderson                 if (vaddr < info->start_code) {
35118e62a717SRichard Henderson                     info->start_code = vaddr;
3512cf129f3aSRichard Henderson                 }
35138e62a717SRichard Henderson                 if (vaddr_ef > info->end_code) {
35148e62a717SRichard Henderson                     info->end_code = vaddr_ef;
35158e62a717SRichard Henderson                 }
35168e62a717SRichard Henderson             }
35178e62a717SRichard Henderson             if (elf_prot & PROT_WRITE) {
35188e62a717SRichard Henderson                 if (vaddr < info->start_data) {
35198e62a717SRichard Henderson                     info->start_data = vaddr;
35208e62a717SRichard Henderson                 }
35218e62a717SRichard Henderson                 if (vaddr_ef > info->end_data) {
35228e62a717SRichard Henderson                     info->end_data = vaddr_ef;
35238e62a717SRichard Henderson                 }
35248a045188STimothy E Baldwin             }
35255dd0db52SStefan Markovic #ifdef TARGET_MIPS
35265dd0db52SStefan Markovic         } else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
35275dd0db52SStefan Markovic             Mips_elf_abiflags_v0 abiflags;
35283bd02386SRichard Henderson 
35293bd02386SRichard Henderson             if (!imgsrc_read(&abiflags, eppnt->p_offset, sizeof(abiflags),
35303bd02386SRichard Henderson                              src, &err)) {
35315dd0db52SStefan Markovic                 goto exit_errmsg;
35325dd0db52SStefan Markovic             }
35335dd0db52SStefan Markovic             bswap_mips_abiflags(&abiflags);
3534c94cb6c9SStefan Markovic             info->fp_abi = abiflags.fp_abi;
35355dd0db52SStefan Markovic #endif
35368e62a717SRichard Henderson         }
35378e62a717SRichard Henderson     }
35388e62a717SRichard Henderson 
35398e62a717SRichard Henderson     if (info->end_data == 0) {
35408e62a717SRichard Henderson         info->start_data = info->end_code;
35418e62a717SRichard Henderson         info->end_data = info->end_code;
354231e31b8aSbellard     }
354331e31b8aSbellard 
3544682674b8SRichard Henderson     if (qemu_log_enabled()) {
354586cf82dcSRichard Henderson         load_symbols(ehdr, src, load_bias);
3546682674b8SRichard Henderson     }
354731e31b8aSbellard 
35483bd02386SRichard Henderson     debuginfo_report_elf(image_name, src->fd, load_bias);
35497c10cb38SIlya Leoshkevich 
355098c1076cSAlex Bennée     mmap_unlock();
355198c1076cSAlex Bennée 
35523bd02386SRichard Henderson     close(src->fd);
35538e62a717SRichard Henderson     return;
355431e31b8aSbellard 
3555c7f17e7bSRichard Henderson  exit_mmap:
3556c7f17e7bSRichard Henderson     error_setg_errno(&err, errno, "Error mapping file");
3557c7f17e7bSRichard Henderson     goto exit_errmsg;
35588e62a717SRichard Henderson  exit_errmsg:
3559c7f17e7bSRichard Henderson     error_reportf_err(err, "%s: ", image_name);
35608e62a717SRichard Henderson     exit(-1);
35618e62a717SRichard Henderson }
35628e62a717SRichard Henderson 
35638e62a717SRichard Henderson static void load_elf_interp(const char *filename, struct image_info *info,
35648e62a717SRichard Henderson                             char bprm_buf[BPRM_BUF_SIZE])
35658e62a717SRichard Henderson {
356640d487eeSRichard Henderson     struct elfhdr ehdr;
35673bd02386SRichard Henderson     ImageSource src;
35688e62a717SRichard Henderson     int fd, retval;
3569808f6563SRichard Henderson     Error *err = NULL;
35708e62a717SRichard Henderson 
35718e62a717SRichard Henderson     fd = open(path(filename), O_RDONLY);
35728e62a717SRichard Henderson     if (fd < 0) {
3573808f6563SRichard Henderson         error_setg_file_open(&err, errno, filename);
3574808f6563SRichard Henderson         error_report_err(err);
3575808f6563SRichard Henderson         exit(-1);
35768e62a717SRichard Henderson     }
35778e62a717SRichard Henderson 
35788e62a717SRichard Henderson     retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
35798e62a717SRichard Henderson     if (retval < 0) {
3580808f6563SRichard Henderson         error_setg_errno(&err, errno, "Error reading file header");
3581808f6563SRichard Henderson         error_reportf_err(err, "%s: ", filename);
3582808f6563SRichard Henderson         exit(-1);
35838e62a717SRichard Henderson     }
3584808f6563SRichard Henderson 
35853bd02386SRichard Henderson     src.fd = fd;
35863bd02386SRichard Henderson     src.cache = bprm_buf;
35873bd02386SRichard Henderson     src.cache_size = retval;
35888e62a717SRichard Henderson 
35893bd02386SRichard Henderson     load_elf_image(filename, &src, info, &ehdr, NULL);
35908e62a717SRichard Henderson }
35918e62a717SRichard Henderson 
3592c40f621aSRichard Henderson #ifdef VDSO_HEADER
3593c40f621aSRichard Henderson #include VDSO_HEADER
3594c40f621aSRichard Henderson #define  vdso_image_info()  &vdso_image_info
3595c40f621aSRichard Henderson #else
3596c40f621aSRichard Henderson #define  vdso_image_info()  NULL
3597c40f621aSRichard Henderson #endif
3598c40f621aSRichard Henderson 
3599c40f621aSRichard Henderson static void load_elf_vdso(struct image_info *info, const VdsoImageInfo *vdso)
3600c40f621aSRichard Henderson {
3601c40f621aSRichard Henderson     ImageSource src;
3602c40f621aSRichard Henderson     struct elfhdr ehdr;
3603c40f621aSRichard Henderson     abi_ulong load_bias, load_addr;
3604c40f621aSRichard Henderson 
3605c40f621aSRichard Henderson     src.fd = -1;
3606c40f621aSRichard Henderson     src.cache = vdso->image;
3607c40f621aSRichard Henderson     src.cache_size = vdso->image_size;
3608c40f621aSRichard Henderson 
3609c40f621aSRichard Henderson     load_elf_image("<internal-vdso>", &src, info, &ehdr, NULL);
3610c40f621aSRichard Henderson     load_addr = info->load_addr;
3611c40f621aSRichard Henderson     load_bias = info->load_bias;
3612c40f621aSRichard Henderson 
3613c40f621aSRichard Henderson     /*
3614c40f621aSRichard Henderson      * We need to relocate the VDSO image.  The one built into the kernel
3615c40f621aSRichard Henderson      * is built for a fixed address.  The one built for QEMU is not, since
3616c40f621aSRichard Henderson      * that requires close control of the guest address space.
3617c40f621aSRichard Henderson      * We pre-processed the image to locate all of the addresses that need
3618c40f621aSRichard Henderson      * to be updated.
3619c40f621aSRichard Henderson      */
3620c40f621aSRichard Henderson     for (unsigned i = 0, n = vdso->reloc_count; i < n; i++) {
3621c40f621aSRichard Henderson         abi_ulong *addr = g2h_untagged(load_addr + vdso->relocs[i]);
3622c40f621aSRichard Henderson         *addr = tswapal(tswapal(*addr) + load_bias);
3623c40f621aSRichard Henderson     }
3624c40f621aSRichard Henderson 
3625c40f621aSRichard Henderson     /* Install signal trampolines, if present. */
3626c40f621aSRichard Henderson     if (vdso->sigreturn_ofs) {
3627c40f621aSRichard Henderson         default_sigreturn = load_addr + vdso->sigreturn_ofs;
3628c40f621aSRichard Henderson     }
3629c40f621aSRichard Henderson     if (vdso->rt_sigreturn_ofs) {
3630c40f621aSRichard Henderson         default_rt_sigreturn = load_addr + vdso->rt_sigreturn_ofs;
3631c40f621aSRichard Henderson     }
3632c40f621aSRichard Henderson 
3633c40f621aSRichard Henderson     /* Remove write from VDSO segment. */
3634c40f621aSRichard Henderson     target_mprotect(info->start_data, info->end_data - info->start_data,
3635c40f621aSRichard Henderson                     PROT_READ | PROT_EXEC);
363631e31b8aSbellard }
363731e31b8aSbellard 
363849918a75Spbrook static int symfind(const void *s0, const void *s1)
363949918a75Spbrook {
364049918a75Spbrook     struct elf_sym *sym = (struct elf_sym *)s1;
3641b6235a75SRichard Henderson     __typeof(sym->st_value) addr = *(uint64_t *)s0;
364249918a75Spbrook     int result = 0;
3643b6235a75SRichard Henderson 
3644c7c530cdSStefan Weil     if (addr < sym->st_value) {
364549918a75Spbrook         result = -1;
3646c7c530cdSStefan Weil     } else if (addr >= sym->st_value + sym->st_size) {
364749918a75Spbrook         result = 1;
364849918a75Spbrook     }
364949918a75Spbrook     return result;
365049918a75Spbrook }
365149918a75Spbrook 
3652b6235a75SRichard Henderson static const char *lookup_symbolxx(struct syminfo *s, uint64_t orig_addr)
365349918a75Spbrook {
365449918a75Spbrook #if ELF_CLASS == ELFCLASS32
365549918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf32;
365649918a75Spbrook #else
365749918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf64;
365849918a75Spbrook #endif
365949918a75Spbrook 
366049918a75Spbrook     // binary search
366149918a75Spbrook     struct elf_sym *sym;
366249918a75Spbrook 
3663c7c530cdSStefan Weil     sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
36647cba04f6SBlue Swirl     if (sym != NULL) {
366549918a75Spbrook         return s->disas_strtab + sym->st_name;
366649918a75Spbrook     }
366749918a75Spbrook 
366849918a75Spbrook     return "";
366949918a75Spbrook }
367049918a75Spbrook 
367149918a75Spbrook /* FIXME: This should use elf_ops.h  */
367249918a75Spbrook static int symcmp(const void *s0, const void *s1)
367349918a75Spbrook {
367449918a75Spbrook     struct elf_sym *sym0 = (struct elf_sym *)s0;
367549918a75Spbrook     struct elf_sym *sym1 = (struct elf_sym *)s1;
367649918a75Spbrook     return (sym0->st_value < sym1->st_value)
367749918a75Spbrook         ? -1
367849918a75Spbrook         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
367949918a75Spbrook }
368049918a75Spbrook 
3681689f936fSbellard /* Best attempt to load symbols from this ELF object. */
368286cf82dcSRichard Henderson static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
368386cf82dcSRichard Henderson                          abi_ulong load_bias)
3684689f936fSbellard {
3685682674b8SRichard Henderson     int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
368686cf82dcSRichard Henderson     g_autofree struct elf_shdr *shdr = NULL;
3687b9475279SCédric VINCENT     char *strings = NULL;
368886cf82dcSRichard Henderson     struct elf_sym *syms = NULL;
368986cf82dcSRichard Henderson     struct elf_sym *new_syms;
369086cf82dcSRichard Henderson     uint64_t segsz;
369131e31b8aSbellard 
3692682674b8SRichard Henderson     shnum = hdr->e_shnum;
369386cf82dcSRichard Henderson     shdr = imgsrc_read_alloc(hdr->e_shoff, shnum * sizeof(struct elf_shdr),
369486cf82dcSRichard Henderson                              src, NULL);
369586cf82dcSRichard Henderson     if (shdr == NULL) {
3696689f936fSbellard         return;
3697682674b8SRichard Henderson     }
3698682674b8SRichard Henderson 
3699682674b8SRichard Henderson     bswap_shdr(shdr, shnum);
3700682674b8SRichard Henderson     for (i = 0; i < shnum; ++i) {
3701682674b8SRichard Henderson         if (shdr[i].sh_type == SHT_SYMTAB) {
3702682674b8SRichard Henderson             sym_idx = i;
3703682674b8SRichard Henderson             str_idx = shdr[i].sh_link;
3704689f936fSbellard             goto found;
3705689f936fSbellard         }
3706689f936fSbellard     }
3707682674b8SRichard Henderson 
3708682674b8SRichard Henderson     /* There will be no symbol table if the file was stripped.  */
3709682674b8SRichard Henderson     return;
3710689f936fSbellard 
3711689f936fSbellard  found:
3712689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them.  */
3713682674b8SRichard Henderson 
37141e06262dSPeter Maydell     segsz = shdr[str_idx].sh_size;
371586cf82dcSRichard Henderson     strings = g_try_malloc(segsz);
371686cf82dcSRichard Henderson     if (!strings) {
371786cf82dcSRichard Henderson         goto give_up;
371886cf82dcSRichard Henderson     }
371986cf82dcSRichard Henderson     if (!imgsrc_read(strings, shdr[str_idx].sh_offset, segsz, src, NULL)) {
3720b9475279SCédric VINCENT         goto give_up;
3721682674b8SRichard Henderson     }
3722689f936fSbellard 
37231e06262dSPeter Maydell     segsz = shdr[sym_idx].sh_size;
37241e06262dSPeter Maydell     if (segsz / sizeof(struct elf_sym) > INT_MAX) {
372586cf82dcSRichard Henderson         /*
372686cf82dcSRichard Henderson          * Implausibly large symbol table: give up rather than ploughing
372786cf82dcSRichard Henderson          * on with the number of symbols calculation overflowing.
37281e06262dSPeter Maydell          */
37291e06262dSPeter Maydell         goto give_up;
37301e06262dSPeter Maydell     }
37311e06262dSPeter Maydell     nsyms = segsz / sizeof(struct elf_sym);
373286cf82dcSRichard Henderson     syms = g_try_malloc(segsz);
373386cf82dcSRichard Henderson     if (!syms) {
373486cf82dcSRichard Henderson         goto give_up;
373586cf82dcSRichard Henderson     }
373686cf82dcSRichard Henderson     if (!imgsrc_read(syms, shdr[sym_idx].sh_offset, segsz, src, NULL)) {
373786cf82dcSRichard Henderson         goto give_up;
373886cf82dcSRichard Henderson     }
373986cf82dcSRichard Henderson 
3740682674b8SRichard Henderson     for (i = 0; i < nsyms; ) {
374149918a75Spbrook         bswap_sym(syms + i);
3742682674b8SRichard Henderson         /* Throw away entries which we do not need.  */
3743682674b8SRichard Henderson         if (syms[i].st_shndx == SHN_UNDEF
3744682674b8SRichard Henderson             || syms[i].st_shndx >= SHN_LORESERVE
3745682674b8SRichard Henderson             || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
3746682674b8SRichard Henderson             if (i < --nsyms) {
374749918a75Spbrook                 syms[i] = syms[nsyms];
374849918a75Spbrook             }
3749682674b8SRichard Henderson         } else {
375049918a75Spbrook #if defined(TARGET_ARM) || defined (TARGET_MIPS)
375149918a75Spbrook             /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
375249918a75Spbrook             syms[i].st_value &= ~(target_ulong)1;
375349918a75Spbrook #endif
3754682674b8SRichard Henderson             syms[i].st_value += load_bias;
375549918a75Spbrook             i++;
375649918a75Spbrook         }
3757682674b8SRichard Henderson     }
375849918a75Spbrook 
3759b9475279SCédric VINCENT     /* No "useful" symbol.  */
3760b9475279SCédric VINCENT     if (nsyms == 0) {
3761b9475279SCédric VINCENT         goto give_up;
3762b9475279SCédric VINCENT     }
3763b9475279SCédric VINCENT 
376486cf82dcSRichard Henderson     /*
376586cf82dcSRichard Henderson      * Attempt to free the storage associated with the local symbols
376686cf82dcSRichard Henderson      * that we threw away.  Whether or not this has any effect on the
376786cf82dcSRichard Henderson      * memory allocation depends on the malloc implementation and how
376886cf82dcSRichard Henderson      * many symbols we managed to discard.
376986cf82dcSRichard Henderson      */
37700ef9ea29SPeter Maydell     new_syms = g_try_renew(struct elf_sym, syms, nsyms);
37718d79de6eSStefan Weil     if (new_syms == NULL) {
3772b9475279SCédric VINCENT         goto give_up;
37735d5c9930SRichard Henderson     }
37748d79de6eSStefan Weil     syms = new_syms;
37755d5c9930SRichard Henderson 
377649918a75Spbrook     qsort(syms, nsyms, sizeof(*syms), symcmp);
377749918a75Spbrook 
377886cf82dcSRichard Henderson     {
377986cf82dcSRichard Henderson         struct syminfo *s = g_new(struct syminfo, 1);
378086cf82dcSRichard Henderson 
378186cf82dcSRichard Henderson         s->disas_strtab = strings;
378249918a75Spbrook         s->disas_num_syms = nsyms;
378349918a75Spbrook #if ELF_CLASS == ELFCLASS32
378449918a75Spbrook         s->disas_symtab.elf32 = syms;
378549918a75Spbrook #else
378649918a75Spbrook         s->disas_symtab.elf64 = syms;
378749918a75Spbrook #endif
3788682674b8SRichard Henderson         s->lookup_symbol = lookup_symbolxx;
3789e80cfcfcSbellard         s->next = syminfos;
3790e80cfcfcSbellard         syminfos = s;
379186cf82dcSRichard Henderson     }
3792b9475279SCédric VINCENT     return;
3793b9475279SCédric VINCENT 
3794b9475279SCédric VINCENT  give_up:
37950ef9ea29SPeter Maydell     g_free(strings);
37960ef9ea29SPeter Maydell     g_free(syms);
3797689f936fSbellard }
379831e31b8aSbellard 
3799768fe76eSYunQiang Su uint32_t get_elf_eflags(int fd)
3800768fe76eSYunQiang Su {
3801768fe76eSYunQiang Su     struct elfhdr ehdr;
3802768fe76eSYunQiang Su     off_t offset;
3803768fe76eSYunQiang Su     int ret;
3804768fe76eSYunQiang Su 
3805768fe76eSYunQiang Su     /* Read ELF header */
3806768fe76eSYunQiang Su     offset = lseek(fd, 0, SEEK_SET);
3807768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3808768fe76eSYunQiang Su         return 0;
3809768fe76eSYunQiang Su     }
3810768fe76eSYunQiang Su     ret = read(fd, &ehdr, sizeof(ehdr));
3811768fe76eSYunQiang Su     if (ret < sizeof(ehdr)) {
3812768fe76eSYunQiang Su         return 0;
3813768fe76eSYunQiang Su     }
3814768fe76eSYunQiang Su     offset = lseek(fd, offset, SEEK_SET);
3815768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3816768fe76eSYunQiang Su         return 0;
3817768fe76eSYunQiang Su     }
3818768fe76eSYunQiang Su 
3819768fe76eSYunQiang Su     /* Check ELF signature */
3820768fe76eSYunQiang Su     if (!elf_check_ident(&ehdr)) {
3821768fe76eSYunQiang Su         return 0;
3822768fe76eSYunQiang Su     }
3823768fe76eSYunQiang Su 
3824768fe76eSYunQiang Su     /* check header */
3825768fe76eSYunQiang Su     bswap_ehdr(&ehdr);
3826768fe76eSYunQiang Su     if (!elf_check_ehdr(&ehdr)) {
3827768fe76eSYunQiang Su         return 0;
3828768fe76eSYunQiang Su     }
3829768fe76eSYunQiang Su 
3830768fe76eSYunQiang Su     /* return architecture id */
3831768fe76eSYunQiang Su     return ehdr.e_flags;
3832768fe76eSYunQiang Su }
3833768fe76eSYunQiang Su 
3834f0116c54SWill Newton int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
383531e31b8aSbellard {
383640d487eeSRichard Henderson     /*
383740d487eeSRichard Henderson      * We need a copy of the elf header for passing to create_elf_tables.
383840d487eeSRichard Henderson      * We will have overwritten the original when we re-use bprm->buf
383940d487eeSRichard Henderson      * while loading the interpreter.  Allocate the storage for this now
384040d487eeSRichard Henderson      * and let elf_load_image do any swapping that may be required.
384140d487eeSRichard Henderson      */
384240d487eeSRichard Henderson     struct elfhdr ehdr;
3843c40f621aSRichard Henderson     struct image_info interp_info, vdso_info;
38448e62a717SRichard Henderson     char *elf_interpreter = NULL;
384559baae9aSStefan Brüns     char *scratch;
384631e31b8aSbellard 
3847abcac736SDaniel Santos     memset(&interp_info, 0, sizeof(interp_info));
3848abcac736SDaniel Santos #ifdef TARGET_MIPS
3849abcac736SDaniel Santos     interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
3850abcac736SDaniel Santos #endif
3851abcac736SDaniel Santos 
38523bd02386SRichard Henderson     load_elf_image(bprm->filename, &bprm->src, info, &ehdr, &elf_interpreter);
385331e31b8aSbellard 
385459baae9aSStefan Brüns     /* Do this so that we can load the interpreter, if need be.  We will
385559baae9aSStefan Brüns        change some of these later */
385659baae9aSStefan Brüns     bprm->p = setup_arg_pages(bprm, info);
385759baae9aSStefan Brüns 
385859baae9aSStefan Brüns     scratch = g_new0(char, TARGET_PAGE_SIZE);
38597c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
386059baae9aSStefan Brüns         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
386159baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
38627c4ee5bcSRichard Henderson         info->file_string = bprm->p;
386359baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
386459baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
38657c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
386659baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
386759baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
38687c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
38697c4ee5bcSRichard Henderson     } else {
38707c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
38717c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
38727c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
38737c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
38747c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
38757c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
38767c4ee5bcSRichard Henderson         info->file_string = bprm->p;
38777c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
38787c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
38797c4ee5bcSRichard Henderson     }
38807c4ee5bcSRichard Henderson 
388159baae9aSStefan Brüns     g_free(scratch);
388259baae9aSStefan Brüns 
3883e5fe0c52Spbrook     if (!bprm->p) {
3884bf858897SRichard Henderson         fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
388531e31b8aSbellard         exit(-1);
38869955ffacSRichard Henderson     }
3887379f6698SPaul Brook 
38888e62a717SRichard Henderson     if (elf_interpreter) {
38898e62a717SRichard Henderson         load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
389031e31b8aSbellard 
38911f356e8cSHelge Deller         /*
38921f356e8cSHelge Deller          * While unusual because of ELF_ET_DYN_BASE, if we are unlucky
38931f356e8cSHelge Deller          * with the mappings the interpreter can be loaded above but
38941f356e8cSHelge Deller          * near the main executable, which can leave very little room
38951f356e8cSHelge Deller          * for the heap.
38961f356e8cSHelge Deller          * If the current brk has less than 16MB, use the end of the
38971f356e8cSHelge Deller          * interpreter.
38981f356e8cSHelge Deller          */
38991f356e8cSHelge Deller         if (interp_info.brk > info->brk &&
39001f356e8cSHelge Deller             interp_info.load_bias - info->brk < 16 * MiB)  {
39011f356e8cSHelge Deller             info->brk = interp_info.brk;
39021f356e8cSHelge Deller         }
39031f356e8cSHelge Deller 
39048e62a717SRichard Henderson         /* If the program interpreter is one of these two, then assume
39058e62a717SRichard Henderson            an iBCS2 image.  Otherwise assume a native linux image.  */
390631e31b8aSbellard 
39078e62a717SRichard Henderson         if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
39088e62a717SRichard Henderson             || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
39098e62a717SRichard Henderson             info->personality = PER_SVR4;
39108e62a717SRichard Henderson 
391131e31b8aSbellard             /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
39128e62a717SRichard Henderson                and some applications "depend" upon this behavior.  Since
39138e62a717SRichard Henderson                we do not have the power to recompile these, we emulate
39148e62a717SRichard Henderson                the SVr4 behavior.  Sigh.  */
39158e62a717SRichard Henderson             target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
391668754b44SPeter Maydell                         MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
391731e31b8aSbellard         }
3918c94cb6c9SStefan Markovic #ifdef TARGET_MIPS
3919c94cb6c9SStefan Markovic         info->interp_fp_abi = interp_info.fp_abi;
3920c94cb6c9SStefan Markovic #endif
39218e62a717SRichard Henderson     }
392231e31b8aSbellard 
3923db2af69dSRichard Henderson     /*
3924c40f621aSRichard Henderson      * Load a vdso if available, which will amongst other things contain the
3925c40f621aSRichard Henderson      * signal trampolines.  Otherwise, allocate a separate page for them.
3926db2af69dSRichard Henderson      */
3927c40f621aSRichard Henderson     const VdsoImageInfo *vdso = vdso_image_info();
3928c40f621aSRichard Henderson     if (vdso) {
3929c40f621aSRichard Henderson         load_elf_vdso(&vdso_info, vdso);
39305d94c2ffSRichard Henderson         info->vdso = vdso_info.load_bias;
3931c40f621aSRichard Henderson     } else if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
3932802ae45eSLaurent Vivier         abi_long tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
3933db2af69dSRichard Henderson                                           PROT_READ | PROT_WRITE,
3934db2af69dSRichard Henderson                                           MAP_PRIVATE | MAP_ANON, -1, 0);
3935802ae45eSLaurent Vivier         if (tramp_page == -1) {
3936802ae45eSLaurent Vivier             return -errno;
3937802ae45eSLaurent Vivier         }
3938802ae45eSLaurent Vivier 
3939db2af69dSRichard Henderson         setup_sigtramp(tramp_page);
3940db2af69dSRichard Henderson         target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
3941db2af69dSRichard Henderson     }
3942db2af69dSRichard Henderson 
3943c40f621aSRichard Henderson     bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &ehdr, info,
3944c40f621aSRichard Henderson                                 elf_interpreter ? &interp_info : NULL,
3945c40f621aSRichard Henderson                                 vdso ? &vdso_info : NULL);
39468e62a717SRichard Henderson     info->start_stack = bprm->p;
39478e62a717SRichard Henderson 
39488e62a717SRichard Henderson     /* If we have an interpreter, set that as the program's entry point.
39498e78064eSRichard Henderson        Copy the load_bias as well, to help PPC64 interpret the entry
39508e62a717SRichard Henderson        point as a function descriptor.  Do this after creating elf tables
39518e62a717SRichard Henderson        so that we copy the original program entry point into the AUXV.  */
39528e62a717SRichard Henderson     if (elf_interpreter) {
39538e78064eSRichard Henderson         info->load_bias = interp_info.load_bias;
39548e62a717SRichard Henderson         info->entry = interp_info.entry;
39552b323087SPhilippe Mathieu-Daudé         g_free(elf_interpreter);
39568e62a717SRichard Henderson     }
395731e31b8aSbellard 
3958edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3959edf8e2afSMika Westerberg     bprm->core_dump = &elf_core_dump;
3960edf8e2afSMika Westerberg #endif
3961edf8e2afSMika Westerberg 
396231e31b8aSbellard     return 0;
396331e31b8aSbellard }
396431e31b8aSbellard 
3965edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3966edf8e2afSMika Westerberg /*
3967edf8e2afSMika Westerberg  * Definitions to generate Intel SVR4-like core files.
3968a2547a13SLaurent Desnogues  * These mostly have the same names as the SVR4 types with "target_elf_"
3969edf8e2afSMika Westerberg  * tacked on the front to prevent clashes with linux definitions,
3970edf8e2afSMika Westerberg  * and the typedef forms have been avoided.  This is mostly like
3971edf8e2afSMika Westerberg  * the SVR4 structure, but more Linuxy, with things that Linux does
3972edf8e2afSMika Westerberg  * not support and which gdb doesn't really use excluded.
3973edf8e2afSMika Westerberg  *
3974edf8e2afSMika Westerberg  * Fields we don't dump (their contents is zero) in linux-user qemu
3975edf8e2afSMika Westerberg  * are marked with XXX.
3976edf8e2afSMika Westerberg  *
3977edf8e2afSMika Westerberg  * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
3978edf8e2afSMika Westerberg  *
3979edf8e2afSMika Westerberg  * Porting ELF coredump for target is (quite) simple process.  First you
3980dd0a3651SNathan Froyd  * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
3981edf8e2afSMika Westerberg  * the target resides):
3982edf8e2afSMika Westerberg  *
3983edf8e2afSMika Westerberg  * #define USE_ELF_CORE_DUMP
3984edf8e2afSMika Westerberg  *
3985edf8e2afSMika Westerberg  * Next you define type of register set used for dumping.  ELF specification
3986edf8e2afSMika Westerberg  * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
3987edf8e2afSMika Westerberg  *
3988c227f099SAnthony Liguori  * typedef <target_regtype> target_elf_greg_t;
3989edf8e2afSMika Westerberg  * #define ELF_NREG <number of registers>
3990c227f099SAnthony Liguori  * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
3991edf8e2afSMika Westerberg  *
3992edf8e2afSMika Westerberg  * Last step is to implement target specific function that copies registers
3993edf8e2afSMika Westerberg  * from given cpu into just specified register set.  Prototype is:
3994edf8e2afSMika Westerberg  *
3995c227f099SAnthony Liguori  * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
39969349b4f9SAndreas Färber  *                                const CPUArchState *env);
3997edf8e2afSMika Westerberg  *
3998edf8e2afSMika Westerberg  * Parameters:
3999edf8e2afSMika Westerberg  *     regs - copy register values into here (allocated and zeroed by caller)
4000edf8e2afSMika Westerberg  *     env - copy registers from here
4001edf8e2afSMika Westerberg  *
4002edf8e2afSMika Westerberg  * Example for ARM target is provided in this file.
4003edf8e2afSMika Westerberg  */
4004edf8e2afSMika Westerberg 
4005edf8e2afSMika Westerberg /* An ELF note in memory */
4006edf8e2afSMika Westerberg struct memelfnote {
4007edf8e2afSMika Westerberg     const char *name;
4008edf8e2afSMika Westerberg     size_t     namesz;
4009edf8e2afSMika Westerberg     size_t     namesz_rounded;
4010edf8e2afSMika Westerberg     int        type;
4011edf8e2afSMika Westerberg     size_t     datasz;
401280f5ce75SLaurent Vivier     size_t     datasz_rounded;
4013edf8e2afSMika Westerberg     void       *data;
4014edf8e2afSMika Westerberg     size_t     notesz;
4015edf8e2afSMika Westerberg };
4016edf8e2afSMika Westerberg 
4017a2547a13SLaurent Desnogues struct target_elf_siginfo {
4018f8fd4fc4SPaolo Bonzini     abi_int    si_signo; /* signal number */
4019f8fd4fc4SPaolo Bonzini     abi_int    si_code;  /* extra code */
4020f8fd4fc4SPaolo Bonzini     abi_int    si_errno; /* errno */
4021edf8e2afSMika Westerberg };
4022edf8e2afSMika Westerberg 
4023a2547a13SLaurent Desnogues struct target_elf_prstatus {
4024a2547a13SLaurent Desnogues     struct target_elf_siginfo pr_info;      /* Info associated with signal */
40251ddd592fSPaolo Bonzini     abi_short          pr_cursig;    /* Current signal */
4026ca98ac83SPaolo Bonzini     abi_ulong          pr_sigpend;   /* XXX */
4027ca98ac83SPaolo Bonzini     abi_ulong          pr_sighold;   /* XXX */
4028c227f099SAnthony Liguori     target_pid_t       pr_pid;
4029c227f099SAnthony Liguori     target_pid_t       pr_ppid;
4030c227f099SAnthony Liguori     target_pid_t       pr_pgrp;
4031c227f099SAnthony Liguori     target_pid_t       pr_sid;
4032edf8e2afSMika Westerberg     struct target_timeval pr_utime;  /* XXX User time */
4033edf8e2afSMika Westerberg     struct target_timeval pr_stime;  /* XXX System time */
4034edf8e2afSMika Westerberg     struct target_timeval pr_cutime; /* XXX Cumulative user time */
4035edf8e2afSMika Westerberg     struct target_timeval pr_cstime; /* XXX Cumulative system time */
4036c227f099SAnthony Liguori     target_elf_gregset_t      pr_reg;       /* GP registers */
4037f8fd4fc4SPaolo Bonzini     abi_int            pr_fpvalid;   /* XXX */
4038edf8e2afSMika Westerberg };
4039edf8e2afSMika Westerberg 
4040edf8e2afSMika Westerberg #define ELF_PRARGSZ     (80) /* Number of chars for args */
4041edf8e2afSMika Westerberg 
4042a2547a13SLaurent Desnogues struct target_elf_prpsinfo {
4043edf8e2afSMika Westerberg     char         pr_state;       /* numeric process state */
4044edf8e2afSMika Westerberg     char         pr_sname;       /* char for pr_state */
4045edf8e2afSMika Westerberg     char         pr_zomb;        /* zombie */
4046edf8e2afSMika Westerberg     char         pr_nice;        /* nice val */
4047ca98ac83SPaolo Bonzini     abi_ulong    pr_flag;        /* flags */
4048c227f099SAnthony Liguori     target_uid_t pr_uid;
4049c227f099SAnthony Liguori     target_gid_t pr_gid;
4050c227f099SAnthony Liguori     target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
4051edf8e2afSMika Westerberg     /* Lots missing */
4052d7eb2b92SAlistair Francis     char    pr_fname[16] QEMU_NONSTRING; /* filename of executable */
4053edf8e2afSMika Westerberg     char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
4054edf8e2afSMika Westerberg };
4055edf8e2afSMika Westerberg 
4056edf8e2afSMika Westerberg /* Here is the structure in which status of each thread is captured. */
4057edf8e2afSMika Westerberg struct elf_thread_status {
405872cf2d4fSBlue Swirl     QTAILQ_ENTRY(elf_thread_status)  ets_link;
4059a2547a13SLaurent Desnogues     struct target_elf_prstatus prstatus;   /* NT_PRSTATUS */
4060edf8e2afSMika Westerberg #if 0
4061edf8e2afSMika Westerberg     elf_fpregset_t fpu;             /* NT_PRFPREG */
4062edf8e2afSMika Westerberg     struct task_struct *thread;
4063edf8e2afSMika Westerberg     elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
4064edf8e2afSMika Westerberg #endif
4065edf8e2afSMika Westerberg     struct memelfnote notes[1];
4066edf8e2afSMika Westerberg     int num_notes;
4067edf8e2afSMika Westerberg };
4068edf8e2afSMika Westerberg 
4069edf8e2afSMika Westerberg struct elf_note_info {
4070edf8e2afSMika Westerberg     struct memelfnote   *notes;
4071a2547a13SLaurent Desnogues     struct target_elf_prstatus *prstatus;  /* NT_PRSTATUS */
4072a2547a13SLaurent Desnogues     struct target_elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
4073edf8e2afSMika Westerberg 
4074b58deb34SPaolo Bonzini     QTAILQ_HEAD(, elf_thread_status) thread_list;
4075edf8e2afSMika Westerberg #if 0
4076edf8e2afSMika Westerberg     /*
4077edf8e2afSMika Westerberg      * Current version of ELF coredump doesn't support
4078edf8e2afSMika Westerberg      * dumping fp regs etc.
4079edf8e2afSMika Westerberg      */
4080edf8e2afSMika Westerberg     elf_fpregset_t *fpu;
4081edf8e2afSMika Westerberg     elf_fpxregset_t *xfpu;
4082edf8e2afSMika Westerberg     int thread_status_size;
4083edf8e2afSMika Westerberg #endif
4084edf8e2afSMika Westerberg     int notes_size;
4085edf8e2afSMika Westerberg     int numnote;
4086edf8e2afSMika Westerberg };
4087edf8e2afSMika Westerberg 
4088edf8e2afSMika Westerberg struct vm_area_struct {
40891a1c4db9SMikhail Ilyin     target_ulong   vma_start;  /* start vaddr of memory region */
40901a1c4db9SMikhail Ilyin     target_ulong   vma_end;    /* end vaddr of memory region */
4091edf8e2afSMika Westerberg     abi_ulong      vma_flags;  /* protection etc. flags for the region */
409272cf2d4fSBlue Swirl     QTAILQ_ENTRY(vm_area_struct) vma_link;
4093edf8e2afSMika Westerberg };
4094edf8e2afSMika Westerberg 
4095edf8e2afSMika Westerberg struct mm_struct {
409672cf2d4fSBlue Swirl     QTAILQ_HEAD(, vm_area_struct) mm_mmap;
4097edf8e2afSMika Westerberg     int mm_count;           /* number of mappings */
4098edf8e2afSMika Westerberg };
4099edf8e2afSMika Westerberg 
4100edf8e2afSMika Westerberg static struct mm_struct *vma_init(void);
4101edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *);
41021a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *, target_ulong,
41031a1c4db9SMikhail Ilyin                            target_ulong, abi_ulong);
4104edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *);
4105edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *);
4106edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *);
4107edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *);
41081a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
4109edf8e2afSMika Westerberg                       unsigned long flags);
4110edf8e2afSMika Westerberg 
4111edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
4112edf8e2afSMika Westerberg static void fill_note(struct memelfnote *, const char *, int,
4113edf8e2afSMika Westerberg                       unsigned int, void *);
4114a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
4115a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
4116edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *, const TaskState *);
4117edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
4118edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *);
4119edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *);
41209349b4f9SAndreas Färber static int fill_note_info(struct elf_note_info *, long, const CPUArchState *);
41219349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *, const CPUArchState *);
4122edf8e2afSMika Westerberg 
4123edf8e2afSMika Westerberg static int dump_write(int, const void *, size_t);
4124edf8e2afSMika Westerberg static int write_note(struct memelfnote *, int);
4125edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *, int);
4126edf8e2afSMika Westerberg 
4127edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
4128a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *prstatus)
4129edf8e2afSMika Westerberg {
4130ca98ac83SPaolo Bonzini     prstatus->pr_info.si_signo = tswap32(prstatus->pr_info.si_signo);
4131ca98ac83SPaolo Bonzini     prstatus->pr_info.si_code = tswap32(prstatus->pr_info.si_code);
4132ca98ac83SPaolo Bonzini     prstatus->pr_info.si_errno = tswap32(prstatus->pr_info.si_errno);
4133edf8e2afSMika Westerberg     prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
4134ca98ac83SPaolo Bonzini     prstatus->pr_sigpend = tswapal(prstatus->pr_sigpend);
4135ca98ac83SPaolo Bonzini     prstatus->pr_sighold = tswapal(prstatus->pr_sighold);
4136edf8e2afSMika Westerberg     prstatus->pr_pid = tswap32(prstatus->pr_pid);
4137edf8e2afSMika Westerberg     prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
4138edf8e2afSMika Westerberg     prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
4139edf8e2afSMika Westerberg     prstatus->pr_sid = tswap32(prstatus->pr_sid);
4140edf8e2afSMika Westerberg     /* cpu times are not filled, so we skip them */
4141edf8e2afSMika Westerberg     /* regs should be in correct format already */
4142edf8e2afSMika Westerberg     prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
4143edf8e2afSMika Westerberg }
4144edf8e2afSMika Westerberg 
4145a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
4146edf8e2afSMika Westerberg {
4147ca98ac83SPaolo Bonzini     psinfo->pr_flag = tswapal(psinfo->pr_flag);
4148edf8e2afSMika Westerberg     psinfo->pr_uid = tswap16(psinfo->pr_uid);
4149edf8e2afSMika Westerberg     psinfo->pr_gid = tswap16(psinfo->pr_gid);
4150edf8e2afSMika Westerberg     psinfo->pr_pid = tswap32(psinfo->pr_pid);
4151edf8e2afSMika Westerberg     psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
4152edf8e2afSMika Westerberg     psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
4153edf8e2afSMika Westerberg     psinfo->pr_sid = tswap32(psinfo->pr_sid);
4154edf8e2afSMika Westerberg }
4155991f8f0cSRichard Henderson 
4156991f8f0cSRichard Henderson static void bswap_note(struct elf_note *en)
4157991f8f0cSRichard Henderson {
4158991f8f0cSRichard Henderson     bswap32s(&en->n_namesz);
4159991f8f0cSRichard Henderson     bswap32s(&en->n_descsz);
4160991f8f0cSRichard Henderson     bswap32s(&en->n_type);
4161991f8f0cSRichard Henderson }
4162991f8f0cSRichard Henderson #else
4163991f8f0cSRichard Henderson static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
4164991f8f0cSRichard Henderson static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
4165991f8f0cSRichard Henderson static inline void bswap_note(struct elf_note *en) { }
4166edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
4167edf8e2afSMika Westerberg 
4168edf8e2afSMika Westerberg /*
4169edf8e2afSMika Westerberg  * Minimal support for linux memory regions.  These are needed
4170edf8e2afSMika Westerberg  * when we are finding out what memory exactly belongs to
4171edf8e2afSMika Westerberg  * emulated process.  No locks needed here, as long as
4172edf8e2afSMika Westerberg  * thread that received the signal is stopped.
4173edf8e2afSMika Westerberg  */
4174edf8e2afSMika Westerberg 
4175edf8e2afSMika Westerberg static struct mm_struct *vma_init(void)
4176edf8e2afSMika Westerberg {
4177edf8e2afSMika Westerberg     struct mm_struct *mm;
4178edf8e2afSMika Westerberg 
41797267c094SAnthony Liguori     if ((mm = g_malloc(sizeof (*mm))) == NULL)
4180edf8e2afSMika Westerberg         return (NULL);
4181edf8e2afSMika Westerberg 
4182edf8e2afSMika Westerberg     mm->mm_count = 0;
418372cf2d4fSBlue Swirl     QTAILQ_INIT(&mm->mm_mmap);
4184edf8e2afSMika Westerberg 
4185edf8e2afSMika Westerberg     return (mm);
4186edf8e2afSMika Westerberg }
4187edf8e2afSMika Westerberg 
4188edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *mm)
4189edf8e2afSMika Westerberg {
4190edf8e2afSMika Westerberg     struct vm_area_struct *vma;
4191edf8e2afSMika Westerberg 
4192edf8e2afSMika Westerberg     while ((vma = vma_first(mm)) != NULL) {
419372cf2d4fSBlue Swirl         QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
41947267c094SAnthony Liguori         g_free(vma);
4195edf8e2afSMika Westerberg     }
41967267c094SAnthony Liguori     g_free(mm);
4197edf8e2afSMika Westerberg }
4198edf8e2afSMika Westerberg 
41991a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *mm, target_ulong start,
42001a1c4db9SMikhail Ilyin                            target_ulong end, abi_ulong flags)
4201edf8e2afSMika Westerberg {
4202edf8e2afSMika Westerberg     struct vm_area_struct *vma;
4203edf8e2afSMika Westerberg 
42047267c094SAnthony Liguori     if ((vma = g_malloc0(sizeof (*vma))) == NULL)
4205edf8e2afSMika Westerberg         return (-1);
4206edf8e2afSMika Westerberg 
4207edf8e2afSMika Westerberg     vma->vma_start = start;
4208edf8e2afSMika Westerberg     vma->vma_end = end;
4209edf8e2afSMika Westerberg     vma->vma_flags = flags;
4210edf8e2afSMika Westerberg 
421172cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
4212edf8e2afSMika Westerberg     mm->mm_count++;
4213edf8e2afSMika Westerberg 
4214edf8e2afSMika Westerberg     return (0);
4215edf8e2afSMika Westerberg }
4216edf8e2afSMika Westerberg 
4217edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *mm)
4218edf8e2afSMika Westerberg {
421972cf2d4fSBlue Swirl     return (QTAILQ_FIRST(&mm->mm_mmap));
4220edf8e2afSMika Westerberg }
4221edf8e2afSMika Westerberg 
4222edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
4223edf8e2afSMika Westerberg {
422472cf2d4fSBlue Swirl     return (QTAILQ_NEXT(vma, vma_link));
4225edf8e2afSMika Westerberg }
4226edf8e2afSMika Westerberg 
4227edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *mm)
4228edf8e2afSMika Westerberg {
4229edf8e2afSMika Westerberg     return (mm->mm_count);
4230edf8e2afSMika Westerberg }
4231edf8e2afSMika Westerberg 
4232edf8e2afSMika Westerberg /*
4233edf8e2afSMika Westerberg  * Calculate file (dump) size of given memory region.
4234edf8e2afSMika Westerberg  */
4235edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
4236edf8e2afSMika Westerberg {
4237edf8e2afSMika Westerberg     /* if we cannot even read the first page, skip it */
4238c7169b02SRichard Henderson     if (!access_ok_untagged(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
4239edf8e2afSMika Westerberg         return (0);
4240edf8e2afSMika Westerberg 
4241edf8e2afSMika Westerberg     /*
4242edf8e2afSMika Westerberg      * Usually we don't dump executable pages as they contain
4243edf8e2afSMika Westerberg      * non-writable code that debugger can read directly from
4244edf8e2afSMika Westerberg      * target library etc.  However, thread stacks are marked
4245edf8e2afSMika Westerberg      * also executable so we read in first page of given region
4246edf8e2afSMika Westerberg      * and check whether it contains elf header.  If there is
4247edf8e2afSMika Westerberg      * no elf header, we dump it.
4248edf8e2afSMika Westerberg      */
4249edf8e2afSMika Westerberg     if (vma->vma_flags & PROT_EXEC) {
4250edf8e2afSMika Westerberg         char page[TARGET_PAGE_SIZE];
4251edf8e2afSMika Westerberg 
4252022625a8SPeter Maydell         if (copy_from_user(page, vma->vma_start, sizeof (page))) {
4253022625a8SPeter Maydell             return 0;
4254022625a8SPeter Maydell         }
4255edf8e2afSMika Westerberg         if ((page[EI_MAG0] == ELFMAG0) &&
4256edf8e2afSMika Westerberg             (page[EI_MAG1] == ELFMAG1) &&
4257edf8e2afSMika Westerberg             (page[EI_MAG2] == ELFMAG2) &&
4258edf8e2afSMika Westerberg             (page[EI_MAG3] == ELFMAG3)) {
4259edf8e2afSMika Westerberg             /*
4260edf8e2afSMika Westerberg              * Mappings are possibly from ELF binary.  Don't dump
4261edf8e2afSMika Westerberg              * them.
4262edf8e2afSMika Westerberg              */
4263edf8e2afSMika Westerberg             return (0);
4264edf8e2afSMika Westerberg         }
4265edf8e2afSMika Westerberg     }
4266edf8e2afSMika Westerberg 
4267edf8e2afSMika Westerberg     return (vma->vma_end - vma->vma_start);
4268edf8e2afSMika Westerberg }
4269edf8e2afSMika Westerberg 
42701a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
4271edf8e2afSMika Westerberg                       unsigned long flags)
4272edf8e2afSMika Westerberg {
4273edf8e2afSMika Westerberg     struct mm_struct *mm = (struct mm_struct *)priv;
4274edf8e2afSMika Westerberg 
4275edf8e2afSMika Westerberg     vma_add_mapping(mm, start, end, flags);
4276edf8e2afSMika Westerberg     return (0);
4277edf8e2afSMika Westerberg }
4278edf8e2afSMika Westerberg 
4279edf8e2afSMika Westerberg static void fill_note(struct memelfnote *note, const char *name, int type,
4280edf8e2afSMika Westerberg                       unsigned int sz, void *data)
4281edf8e2afSMika Westerberg {
4282edf8e2afSMika Westerberg     unsigned int namesz;
4283edf8e2afSMika Westerberg 
4284edf8e2afSMika Westerberg     namesz = strlen(name) + 1;
4285edf8e2afSMika Westerberg     note->name = name;
4286edf8e2afSMika Westerberg     note->namesz = namesz;
4287edf8e2afSMika Westerberg     note->namesz_rounded = roundup(namesz, sizeof (int32_t));
4288edf8e2afSMika Westerberg     note->type = type;
428980f5ce75SLaurent Vivier     note->datasz = sz;
429080f5ce75SLaurent Vivier     note->datasz_rounded = roundup(sz, sizeof (int32_t));
429180f5ce75SLaurent Vivier 
4292edf8e2afSMika Westerberg     note->data = data;
4293edf8e2afSMika Westerberg 
4294edf8e2afSMika Westerberg     /*
4295edf8e2afSMika Westerberg      * We calculate rounded up note size here as specified by
4296edf8e2afSMika Westerberg      * ELF document.
4297edf8e2afSMika Westerberg      */
4298edf8e2afSMika Westerberg     note->notesz = sizeof (struct elf_note) +
429980f5ce75SLaurent Vivier         note->namesz_rounded + note->datasz_rounded;
4300edf8e2afSMika Westerberg }
4301edf8e2afSMika Westerberg 
4302edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
4303edf8e2afSMika Westerberg                             uint32_t flags)
4304edf8e2afSMika Westerberg {
4305edf8e2afSMika Westerberg     (void) memset(elf, 0, sizeof(*elf));
4306edf8e2afSMika Westerberg 
4307edf8e2afSMika Westerberg     (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
4308edf8e2afSMika Westerberg     elf->e_ident[EI_CLASS] = ELF_CLASS;
4309edf8e2afSMika Westerberg     elf->e_ident[EI_DATA] = ELF_DATA;
4310edf8e2afSMika Westerberg     elf->e_ident[EI_VERSION] = EV_CURRENT;
4311edf8e2afSMika Westerberg     elf->e_ident[EI_OSABI] = ELF_OSABI;
4312edf8e2afSMika Westerberg 
4313edf8e2afSMika Westerberg     elf->e_type = ET_CORE;
4314edf8e2afSMika Westerberg     elf->e_machine = machine;
4315edf8e2afSMika Westerberg     elf->e_version = EV_CURRENT;
4316edf8e2afSMika Westerberg     elf->e_phoff = sizeof(struct elfhdr);
4317edf8e2afSMika Westerberg     elf->e_flags = flags;
4318edf8e2afSMika Westerberg     elf->e_ehsize = sizeof(struct elfhdr);
4319edf8e2afSMika Westerberg     elf->e_phentsize = sizeof(struct elf_phdr);
4320edf8e2afSMika Westerberg     elf->e_phnum = segs;
4321edf8e2afSMika Westerberg 
4322edf8e2afSMika Westerberg     bswap_ehdr(elf);
4323edf8e2afSMika Westerberg }
4324edf8e2afSMika Westerberg 
4325edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
4326edf8e2afSMika Westerberg {
4327edf8e2afSMika Westerberg     phdr->p_type = PT_NOTE;
4328edf8e2afSMika Westerberg     phdr->p_offset = offset;
4329edf8e2afSMika Westerberg     phdr->p_vaddr = 0;
4330edf8e2afSMika Westerberg     phdr->p_paddr = 0;
4331edf8e2afSMika Westerberg     phdr->p_filesz = sz;
4332edf8e2afSMika Westerberg     phdr->p_memsz = 0;
4333edf8e2afSMika Westerberg     phdr->p_flags = 0;
4334edf8e2afSMika Westerberg     phdr->p_align = 0;
4335edf8e2afSMika Westerberg 
4336991f8f0cSRichard Henderson     bswap_phdr(phdr, 1);
4337edf8e2afSMika Westerberg }
4338edf8e2afSMika Westerberg 
4339edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *note)
4340edf8e2afSMika Westerberg {
4341edf8e2afSMika Westerberg     return (note->notesz);
4342edf8e2afSMika Westerberg }
4343edf8e2afSMika Westerberg 
4344a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *prstatus,
4345edf8e2afSMika Westerberg                           const TaskState *ts, int signr)
4346edf8e2afSMika Westerberg {
4347edf8e2afSMika Westerberg     (void) memset(prstatus, 0, sizeof (*prstatus));
4348edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
4349edf8e2afSMika Westerberg     prstatus->pr_pid = ts->ts_tid;
4350edf8e2afSMika Westerberg     prstatus->pr_ppid = getppid();
4351edf8e2afSMika Westerberg     prstatus->pr_pgrp = getpgrp();
4352edf8e2afSMika Westerberg     prstatus->pr_sid = getsid(0);
4353edf8e2afSMika Westerberg 
4354edf8e2afSMika Westerberg     bswap_prstatus(prstatus);
4355edf8e2afSMika Westerberg }
4356edf8e2afSMika Westerberg 
4357a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
4358edf8e2afSMika Westerberg {
4359900cfbcaSJim Meyering     char *base_filename;
4360edf8e2afSMika Westerberg     unsigned int i, len;
4361edf8e2afSMika Westerberg 
4362edf8e2afSMika Westerberg     (void) memset(psinfo, 0, sizeof (*psinfo));
4363edf8e2afSMika Westerberg 
43645f779a3aSIlya Leoshkevich     len = ts->info->env_strings - ts->info->arg_strings;
4365edf8e2afSMika Westerberg     if (len >= ELF_PRARGSZ)
4366edf8e2afSMika Westerberg         len = ELF_PRARGSZ - 1;
43675f779a3aSIlya Leoshkevich     if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_strings, len)) {
4368edf8e2afSMika Westerberg         return -EFAULT;
43695f779a3aSIlya Leoshkevich     }
4370edf8e2afSMika Westerberg     for (i = 0; i < len; i++)
4371edf8e2afSMika Westerberg         if (psinfo->pr_psargs[i] == 0)
4372edf8e2afSMika Westerberg             psinfo->pr_psargs[i] = ' ';
4373edf8e2afSMika Westerberg     psinfo->pr_psargs[len] = 0;
4374edf8e2afSMika Westerberg 
4375edf8e2afSMika Westerberg     psinfo->pr_pid = getpid();
4376edf8e2afSMika Westerberg     psinfo->pr_ppid = getppid();
4377edf8e2afSMika Westerberg     psinfo->pr_pgrp = getpgrp();
4378edf8e2afSMika Westerberg     psinfo->pr_sid = getsid(0);
4379edf8e2afSMika Westerberg     psinfo->pr_uid = getuid();
4380edf8e2afSMika Westerberg     psinfo->pr_gid = getgid();
4381edf8e2afSMika Westerberg 
4382900cfbcaSJim Meyering     base_filename = g_path_get_basename(ts->bprm->filename);
4383900cfbcaSJim Meyering     /*
4384900cfbcaSJim Meyering      * Using strncpy here is fine: at max-length,
4385900cfbcaSJim Meyering      * this field is not NUL-terminated.
4386900cfbcaSJim Meyering      */
4387edf8e2afSMika Westerberg     (void) strncpy(psinfo->pr_fname, base_filename,
4388edf8e2afSMika Westerberg                    sizeof(psinfo->pr_fname));
4389edf8e2afSMika Westerberg 
4390900cfbcaSJim Meyering     g_free(base_filename);
4391edf8e2afSMika Westerberg     bswap_psinfo(psinfo);
4392edf8e2afSMika Westerberg     return (0);
4393edf8e2afSMika Westerberg }
4394edf8e2afSMika Westerberg 
4395edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
4396edf8e2afSMika Westerberg {
4397edf8e2afSMika Westerberg     elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
4398edf8e2afSMika Westerberg     elf_addr_t orig_auxv = auxv;
4399edf8e2afSMika Westerberg     void *ptr;
4400125b0f55SAlexander Graf     int len = ts->info->auxv_len;
4401edf8e2afSMika Westerberg 
4402edf8e2afSMika Westerberg     /*
4403edf8e2afSMika Westerberg      * Auxiliary vector is stored in target process stack.  It contains
4404edf8e2afSMika Westerberg      * {type, value} pairs that we need to dump into note.  This is not
4405edf8e2afSMika Westerberg      * strictly necessary but we do it here for sake of completeness.
4406edf8e2afSMika Westerberg      */
4407edf8e2afSMika Westerberg 
4408edf8e2afSMika Westerberg     /* read in whole auxv vector and copy it to memelfnote */
4409edf8e2afSMika Westerberg     ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
4410edf8e2afSMika Westerberg     if (ptr != NULL) {
4411edf8e2afSMika Westerberg         fill_note(note, "CORE", NT_AUXV, len, ptr);
4412edf8e2afSMika Westerberg         unlock_user(ptr, auxv, len);
4413edf8e2afSMika Westerberg     }
4414edf8e2afSMika Westerberg }
4415edf8e2afSMika Westerberg 
4416edf8e2afSMika Westerberg /*
4417edf8e2afSMika Westerberg  * Constructs name of coredump file.  We have following convention
4418edf8e2afSMika Westerberg  * for the name:
4419edf8e2afSMika Westerberg  *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
4420edf8e2afSMika Westerberg  *
442168af19adSDaniel P. Berrangé  * Returns the filename
4422edf8e2afSMika Westerberg  */
442368af19adSDaniel P. Berrangé static char *core_dump_filename(const TaskState *ts)
4424edf8e2afSMika Westerberg {
442568af19adSDaniel P. Berrangé     g_autoptr(GDateTime) now = g_date_time_new_now_local();
442668af19adSDaniel P. Berrangé     g_autofree char *nowstr = g_date_time_format(now, "%Y%m%d-%H%M%S");
442768af19adSDaniel P. Berrangé     g_autofree char *base_filename = g_path_get_basename(ts->bprm->filename);
4428edf8e2afSMika Westerberg 
442968af19adSDaniel P. Berrangé     return g_strdup_printf("qemu_%s_%s_%d.core",
443068af19adSDaniel P. Berrangé                            base_filename, nowstr, (int)getpid());
4431edf8e2afSMika Westerberg }
4432edf8e2afSMika Westerberg 
4433edf8e2afSMika Westerberg static int dump_write(int fd, const void *ptr, size_t size)
4434edf8e2afSMika Westerberg {
4435edf8e2afSMika Westerberg     const char *bufp = (const char *)ptr;
4436edf8e2afSMika Westerberg     ssize_t bytes_written, bytes_left;
4437edf8e2afSMika Westerberg     struct rlimit dumpsize;
4438edf8e2afSMika Westerberg     off_t pos;
4439edf8e2afSMika Westerberg 
4440edf8e2afSMika Westerberg     bytes_written = 0;
4441edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
4442edf8e2afSMika Westerberg     if ((pos = lseek(fd, 0, SEEK_CUR))==-1) {
4443edf8e2afSMika Westerberg         if (errno == ESPIPE) { /* not a seekable stream */
4444edf8e2afSMika Westerberg             bytes_left = size;
4445edf8e2afSMika Westerberg         } else {
4446edf8e2afSMika Westerberg             return pos;
4447edf8e2afSMika Westerberg         }
4448edf8e2afSMika Westerberg     } else {
4449edf8e2afSMika Westerberg         if (dumpsize.rlim_cur <= pos) {
4450edf8e2afSMika Westerberg             return -1;
4451edf8e2afSMika Westerberg         } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
4452edf8e2afSMika Westerberg             bytes_left = size;
4453edf8e2afSMika Westerberg         } else {
4454edf8e2afSMika Westerberg             size_t limit_left=dumpsize.rlim_cur - pos;
4455edf8e2afSMika Westerberg             bytes_left = limit_left >= size ? size : limit_left ;
4456edf8e2afSMika Westerberg         }
4457edf8e2afSMika Westerberg     }
4458edf8e2afSMika Westerberg 
4459edf8e2afSMika Westerberg     /*
4460edf8e2afSMika Westerberg      * In normal conditions, single write(2) should do but
4461edf8e2afSMika Westerberg      * in case of socket etc. this mechanism is more portable.
4462edf8e2afSMika Westerberg      */
4463edf8e2afSMika Westerberg     do {
4464edf8e2afSMika Westerberg         bytes_written = write(fd, bufp, bytes_left);
4465edf8e2afSMika Westerberg         if (bytes_written < 0) {
4466edf8e2afSMika Westerberg             if (errno == EINTR)
4467edf8e2afSMika Westerberg                 continue;
4468edf8e2afSMika Westerberg             return (-1);
4469edf8e2afSMika Westerberg         } else if (bytes_written == 0) { /* eof */
4470edf8e2afSMika Westerberg             return (-1);
4471edf8e2afSMika Westerberg         }
4472edf8e2afSMika Westerberg         bufp += bytes_written;
4473edf8e2afSMika Westerberg         bytes_left -= bytes_written;
4474edf8e2afSMika Westerberg     } while (bytes_left > 0);
4475edf8e2afSMika Westerberg 
4476edf8e2afSMika Westerberg     return (0);
4477edf8e2afSMika Westerberg }
4478edf8e2afSMika Westerberg 
4479edf8e2afSMika Westerberg static int write_note(struct memelfnote *men, int fd)
4480edf8e2afSMika Westerberg {
4481edf8e2afSMika Westerberg     struct elf_note en;
4482edf8e2afSMika Westerberg 
4483edf8e2afSMika Westerberg     en.n_namesz = men->namesz;
4484edf8e2afSMika Westerberg     en.n_type = men->type;
4485edf8e2afSMika Westerberg     en.n_descsz = men->datasz;
4486edf8e2afSMika Westerberg 
4487edf8e2afSMika Westerberg     bswap_note(&en);
4488edf8e2afSMika Westerberg 
4489edf8e2afSMika Westerberg     if (dump_write(fd, &en, sizeof(en)) != 0)
4490edf8e2afSMika Westerberg         return (-1);
4491edf8e2afSMika Westerberg     if (dump_write(fd, men->name, men->namesz_rounded) != 0)
4492edf8e2afSMika Westerberg         return (-1);
449380f5ce75SLaurent Vivier     if (dump_write(fd, men->data, men->datasz_rounded) != 0)
4494edf8e2afSMika Westerberg         return (-1);
4495edf8e2afSMika Westerberg 
4496edf8e2afSMika Westerberg     return (0);
4497edf8e2afSMika Westerberg }
4498edf8e2afSMika Westerberg 
44999349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *info, const CPUArchState *env)
4500edf8e2afSMika Westerberg {
450129a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
45020429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4503edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4504edf8e2afSMika Westerberg 
45057267c094SAnthony Liguori     ets = g_malloc0(sizeof (*ets));
4506edf8e2afSMika Westerberg     ets->num_notes = 1; /* only prstatus is dumped */
4507edf8e2afSMika Westerberg     fill_prstatus(&ets->prstatus, ts, 0);
4508edf8e2afSMika Westerberg     elf_core_copy_regs(&ets->prstatus.pr_reg, env);
4509edf8e2afSMika Westerberg     fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
4510edf8e2afSMika Westerberg               &ets->prstatus);
4511edf8e2afSMika Westerberg 
451272cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
4513edf8e2afSMika Westerberg 
4514edf8e2afSMika Westerberg     info->notes_size += note_size(&ets->notes[0]);
4515edf8e2afSMika Westerberg }
4516edf8e2afSMika Westerberg 
45176afafa86SPeter Maydell static void init_note_info(struct elf_note_info *info)
45186afafa86SPeter Maydell {
45196afafa86SPeter Maydell     /* Initialize the elf_note_info structure so that it is at
45206afafa86SPeter Maydell      * least safe to call free_note_info() on it. Must be
45216afafa86SPeter Maydell      * called before calling fill_note_info().
45226afafa86SPeter Maydell      */
45236afafa86SPeter Maydell     memset(info, 0, sizeof (*info));
45246afafa86SPeter Maydell     QTAILQ_INIT(&info->thread_list);
45256afafa86SPeter Maydell }
45266afafa86SPeter Maydell 
4527edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *info,
45289349b4f9SAndreas Färber                           long signr, const CPUArchState *env)
4529edf8e2afSMika Westerberg {
4530edf8e2afSMika Westerberg #define NUMNOTES 3
453129a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
45320429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4533edf8e2afSMika Westerberg     int i;
4534edf8e2afSMika Westerberg 
4535c78d65e8SMarkus Armbruster     info->notes = g_new0(struct memelfnote, NUMNOTES);
4536edf8e2afSMika Westerberg     if (info->notes == NULL)
4537edf8e2afSMika Westerberg         return (-ENOMEM);
45387267c094SAnthony Liguori     info->prstatus = g_malloc0(sizeof (*info->prstatus));
4539edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4540edf8e2afSMika Westerberg         return (-ENOMEM);
45417267c094SAnthony Liguori     info->psinfo = g_malloc0(sizeof (*info->psinfo));
4542edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4543edf8e2afSMika Westerberg         return (-ENOMEM);
4544edf8e2afSMika Westerberg 
4545edf8e2afSMika Westerberg     /*
4546edf8e2afSMika Westerberg      * First fill in status (and registers) of current thread
4547edf8e2afSMika Westerberg      * including process info & aux vector.
4548edf8e2afSMika Westerberg      */
4549edf8e2afSMika Westerberg     fill_prstatus(info->prstatus, ts, signr);
4550edf8e2afSMika Westerberg     elf_core_copy_regs(&info->prstatus->pr_reg, env);
4551edf8e2afSMika Westerberg     fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
4552edf8e2afSMika Westerberg               sizeof (*info->prstatus), info->prstatus);
4553edf8e2afSMika Westerberg     fill_psinfo(info->psinfo, ts);
4554edf8e2afSMika Westerberg     fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
4555edf8e2afSMika Westerberg               sizeof (*info->psinfo), info->psinfo);
4556edf8e2afSMika Westerberg     fill_auxv_note(&info->notes[2], ts);
4557edf8e2afSMika Westerberg     info->numnote = 3;
4558edf8e2afSMika Westerberg 
4559edf8e2afSMika Westerberg     info->notes_size = 0;
4560edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4561edf8e2afSMika Westerberg         info->notes_size += note_size(&info->notes[i]);
4562edf8e2afSMika Westerberg 
4563edf8e2afSMika Westerberg     /* read and fill status of all threads */
4564370ed600SJamie Iles     WITH_QEMU_LOCK_GUARD(&qemu_cpu_list_lock) {
4565bdc44640SAndreas Färber         CPU_FOREACH(cpu) {
4566a2247f8eSAndreas Färber             if (cpu == thread_cpu) {
4567edf8e2afSMika Westerberg                 continue;
4568182735efSAndreas Färber             }
4569b77af26eSRichard Henderson             fill_thread_info(info, cpu_env(cpu));
4570edf8e2afSMika Westerberg         }
4571370ed600SJamie Iles     }
4572edf8e2afSMika Westerberg 
4573edf8e2afSMika Westerberg     return (0);
4574edf8e2afSMika Westerberg }
4575edf8e2afSMika Westerberg 
4576edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *info)
4577edf8e2afSMika Westerberg {
4578edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4579edf8e2afSMika Westerberg 
458072cf2d4fSBlue Swirl     while (!QTAILQ_EMPTY(&info->thread_list)) {
458172cf2d4fSBlue Swirl         ets = QTAILQ_FIRST(&info->thread_list);
458272cf2d4fSBlue Swirl         QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
45837267c094SAnthony Liguori         g_free(ets);
4584edf8e2afSMika Westerberg     }
4585edf8e2afSMika Westerberg 
45867267c094SAnthony Liguori     g_free(info->prstatus);
45877267c094SAnthony Liguori     g_free(info->psinfo);
45887267c094SAnthony Liguori     g_free(info->notes);
4589edf8e2afSMika Westerberg }
4590edf8e2afSMika Westerberg 
4591edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *info, int fd)
4592edf8e2afSMika Westerberg {
4593edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4594edf8e2afSMika Westerberg     int i, error = 0;
4595edf8e2afSMika Westerberg 
4596edf8e2afSMika Westerberg     /* write prstatus, psinfo and auxv for current thread */
4597edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4598edf8e2afSMika Westerberg         if ((error = write_note(&info->notes[i], fd)) != 0)
4599edf8e2afSMika Westerberg             return (error);
4600edf8e2afSMika Westerberg 
4601edf8e2afSMika Westerberg     /* write prstatus for each thread */
460252a53afeSEmilio G. Cota     QTAILQ_FOREACH(ets, &info->thread_list, ets_link) {
4603edf8e2afSMika Westerberg         if ((error = write_note(&ets->notes[0], fd)) != 0)
4604edf8e2afSMika Westerberg             return (error);
4605edf8e2afSMika Westerberg     }
4606edf8e2afSMika Westerberg 
4607edf8e2afSMika Westerberg     return (0);
4608edf8e2afSMika Westerberg }
4609edf8e2afSMika Westerberg 
4610edf8e2afSMika Westerberg /*
4611edf8e2afSMika Westerberg  * Write out ELF coredump.
4612edf8e2afSMika Westerberg  *
4613edf8e2afSMika Westerberg  * See documentation of ELF object file format in:
4614edf8e2afSMika Westerberg  * http://www.caldera.com/developers/devspecs/gabi41.pdf
4615edf8e2afSMika Westerberg  *
4616edf8e2afSMika Westerberg  * Coredump format in linux is following:
4617edf8e2afSMika Westerberg  *
4618edf8e2afSMika Westerberg  * 0   +----------------------+         \
4619edf8e2afSMika Westerberg  *     | ELF header           | ET_CORE  |
4620edf8e2afSMika Westerberg  *     +----------------------+          |
4621edf8e2afSMika Westerberg  *     | ELF program headers  |          |--- headers
4622edf8e2afSMika Westerberg  *     | - NOTE section       |          |
4623edf8e2afSMika Westerberg  *     | - PT_LOAD sections   |          |
4624edf8e2afSMika Westerberg  *     +----------------------+         /
4625edf8e2afSMika Westerberg  *     | NOTEs:               |
4626edf8e2afSMika Westerberg  *     | - NT_PRSTATUS        |
4627edf8e2afSMika Westerberg  *     | - NT_PRSINFO         |
4628edf8e2afSMika Westerberg  *     | - NT_AUXV            |
4629edf8e2afSMika Westerberg  *     +----------------------+ <-- aligned to target page
4630edf8e2afSMika Westerberg  *     | Process memory dump  |
4631edf8e2afSMika Westerberg  *     :                      :
4632edf8e2afSMika Westerberg  *     .                      .
4633edf8e2afSMika Westerberg  *     :                      :
4634edf8e2afSMika Westerberg  *     |                      |
4635edf8e2afSMika Westerberg  *     +----------------------+
4636edf8e2afSMika Westerberg  *
4637edf8e2afSMika Westerberg  * NT_PRSTATUS -> struct elf_prstatus (per thread)
4638edf8e2afSMika Westerberg  * NT_PRSINFO  -> struct elf_prpsinfo
4639edf8e2afSMika Westerberg  * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
4640edf8e2afSMika Westerberg  *
4641edf8e2afSMika Westerberg  * Format follows System V format as close as possible.  Current
4642edf8e2afSMika Westerberg  * version limitations are as follows:
4643edf8e2afSMika Westerberg  *     - no floating point registers are dumped
4644edf8e2afSMika Westerberg  *
4645edf8e2afSMika Westerberg  * Function returns 0 in case of success, negative errno otherwise.
4646edf8e2afSMika Westerberg  *
4647edf8e2afSMika Westerberg  * TODO: make this work also during runtime: it should be
4648edf8e2afSMika Westerberg  * possible to force coredump from running process and then
4649edf8e2afSMika Westerberg  * continue processing.  For example qemu could set up SIGUSR2
4650edf8e2afSMika Westerberg  * handler (provided that target process haven't registered
4651edf8e2afSMika Westerberg  * handler for that) that does the dump when signal is received.
4652edf8e2afSMika Westerberg  */
46539349b4f9SAndreas Färber static int elf_core_dump(int signr, const CPUArchState *env)
4654edf8e2afSMika Westerberg {
465529a0af61SRichard Henderson     const CPUState *cpu = env_cpu((CPUArchState *)env);
46560429a971SAndreas Färber     const TaskState *ts = (const TaskState *)cpu->opaque;
4657edf8e2afSMika Westerberg     struct vm_area_struct *vma = NULL;
465868af19adSDaniel P. Berrangé     g_autofree char *corefile = NULL;
4659edf8e2afSMika Westerberg     struct elf_note_info info;
4660edf8e2afSMika Westerberg     struct elfhdr elf;
4661edf8e2afSMika Westerberg     struct elf_phdr phdr;
4662edf8e2afSMika Westerberg     struct rlimit dumpsize;
4663edf8e2afSMika Westerberg     struct mm_struct *mm = NULL;
4664edf8e2afSMika Westerberg     off_t offset = 0, data_offset = 0;
4665edf8e2afSMika Westerberg     int segs = 0;
4666edf8e2afSMika Westerberg     int fd = -1;
4667edf8e2afSMika Westerberg 
46686afafa86SPeter Maydell     init_note_info(&info);
46696afafa86SPeter Maydell 
4670edf8e2afSMika Westerberg     errno = 0;
46710ea731dbSThomas Weißschuh 
46720ea731dbSThomas Weißschuh     if (prctl(PR_GET_DUMPABLE) == 0) {
46730ea731dbSThomas Weißschuh         return 0;
46740ea731dbSThomas Weißschuh     }
46750ea731dbSThomas Weißschuh 
4676*f93b9953SRichard Henderson     if (getrlimit(RLIMIT_CORE, &dumpsize) < 0 || dumpsize.rlim_cur == 0) {
4677edf8e2afSMika Westerberg         return 0;
46783805d428SThomas Weißschuh     }
4679edf8e2afSMika Westerberg 
468068af19adSDaniel P. Berrangé     corefile = core_dump_filename(ts);
4681edf8e2afSMika Westerberg 
4682edf8e2afSMika Westerberg     if ((fd = open(corefile, O_WRONLY | O_CREAT,
4683edf8e2afSMika Westerberg                    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
4684edf8e2afSMika Westerberg         return (-errno);
4685edf8e2afSMika Westerberg 
4686edf8e2afSMika Westerberg     /*
4687edf8e2afSMika Westerberg      * Walk through target process memory mappings and
4688edf8e2afSMika Westerberg      * set up structure containing this information.  After
4689edf8e2afSMika Westerberg      * this point vma_xxx functions can be used.
4690edf8e2afSMika Westerberg      */
4691edf8e2afSMika Westerberg     if ((mm = vma_init()) == NULL)
4692edf8e2afSMika Westerberg         goto out;
4693edf8e2afSMika Westerberg 
4694edf8e2afSMika Westerberg     walk_memory_regions(mm, vma_walker);
4695edf8e2afSMika Westerberg     segs = vma_get_mapping_count(mm);
4696edf8e2afSMika Westerberg 
4697edf8e2afSMika Westerberg     /*
4698edf8e2afSMika Westerberg      * Construct valid coredump ELF header.  We also
4699edf8e2afSMika Westerberg      * add one more segment for notes.
4700edf8e2afSMika Westerberg      */
4701edf8e2afSMika Westerberg     fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
4702edf8e2afSMika Westerberg     if (dump_write(fd, &elf, sizeof (elf)) != 0)
4703edf8e2afSMika Westerberg         goto out;
4704edf8e2afSMika Westerberg 
4705b6af0975SDaniel P. Berrange     /* fill in the in-memory version of notes */
4706edf8e2afSMika Westerberg     if (fill_note_info(&info, signr, env) < 0)
4707edf8e2afSMika Westerberg         goto out;
4708edf8e2afSMika Westerberg 
4709edf8e2afSMika Westerberg     offset += sizeof (elf);                             /* elf header */
4710edf8e2afSMika Westerberg     offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
4711edf8e2afSMika Westerberg 
4712edf8e2afSMika Westerberg     /* write out notes program header */
4713edf8e2afSMika Westerberg     fill_elf_note_phdr(&phdr, info.notes_size, offset);
4714edf8e2afSMika Westerberg 
4715edf8e2afSMika Westerberg     offset += info.notes_size;
4716edf8e2afSMika Westerberg     if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
4717edf8e2afSMika Westerberg         goto out;
4718edf8e2afSMika Westerberg 
4719edf8e2afSMika Westerberg     /*
4720edf8e2afSMika Westerberg      * ELF specification wants data to start at page boundary so
4721edf8e2afSMika Westerberg      * we align it here.
4722edf8e2afSMika Westerberg      */
472380f5ce75SLaurent Vivier     data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
4724edf8e2afSMika Westerberg 
4725edf8e2afSMika Westerberg     /*
4726edf8e2afSMika Westerberg      * Write program headers for memory regions mapped in
4727edf8e2afSMika Westerberg      * the target process.
4728edf8e2afSMika Westerberg      */
4729edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4730edf8e2afSMika Westerberg         (void) memset(&phdr, 0, sizeof (phdr));
4731edf8e2afSMika Westerberg 
4732edf8e2afSMika Westerberg         phdr.p_type = PT_LOAD;
4733edf8e2afSMika Westerberg         phdr.p_offset = offset;
4734edf8e2afSMika Westerberg         phdr.p_vaddr = vma->vma_start;
4735edf8e2afSMika Westerberg         phdr.p_paddr = 0;
4736edf8e2afSMika Westerberg         phdr.p_filesz = vma_dump_size(vma);
4737edf8e2afSMika Westerberg         offset += phdr.p_filesz;
4738edf8e2afSMika Westerberg         phdr.p_memsz = vma->vma_end - vma->vma_start;
4739edf8e2afSMika Westerberg         phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
4740edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_WRITE)
4741edf8e2afSMika Westerberg             phdr.p_flags |= PF_W;
4742edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_EXEC)
4743edf8e2afSMika Westerberg             phdr.p_flags |= PF_X;
4744edf8e2afSMika Westerberg         phdr.p_align = ELF_EXEC_PAGESIZE;
4745edf8e2afSMika Westerberg 
474680f5ce75SLaurent Vivier         bswap_phdr(&phdr, 1);
4747772034b6SPeter Maydell         if (dump_write(fd, &phdr, sizeof(phdr)) != 0) {
4748772034b6SPeter Maydell             goto out;
4749772034b6SPeter Maydell         }
4750edf8e2afSMika Westerberg     }
4751edf8e2afSMika Westerberg 
4752edf8e2afSMika Westerberg     /*
4753edf8e2afSMika Westerberg      * Next we write notes just after program headers.  No
4754edf8e2afSMika Westerberg      * alignment needed here.
4755edf8e2afSMika Westerberg      */
4756edf8e2afSMika Westerberg     if (write_note_info(&info, fd) < 0)
4757edf8e2afSMika Westerberg         goto out;
4758edf8e2afSMika Westerberg 
4759edf8e2afSMika Westerberg     /* align data to page boundary */
4760edf8e2afSMika Westerberg     if (lseek(fd, data_offset, SEEK_SET) != data_offset)
4761edf8e2afSMika Westerberg         goto out;
4762edf8e2afSMika Westerberg 
4763edf8e2afSMika Westerberg     /*
4764edf8e2afSMika Westerberg      * Finally we can dump process memory into corefile as well.
4765edf8e2afSMika Westerberg      */
4766edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4767edf8e2afSMika Westerberg         abi_ulong addr;
4768edf8e2afSMika Westerberg         abi_ulong end;
4769edf8e2afSMika Westerberg 
4770edf8e2afSMika Westerberg         end = vma->vma_start + vma_dump_size(vma);
4771edf8e2afSMika Westerberg 
4772edf8e2afSMika Westerberg         for (addr = vma->vma_start; addr < end;
4773edf8e2afSMika Westerberg              addr += TARGET_PAGE_SIZE) {
4774edf8e2afSMika Westerberg             char page[TARGET_PAGE_SIZE];
4775edf8e2afSMika Westerberg             int error;
4776edf8e2afSMika Westerberg 
4777edf8e2afSMika Westerberg             /*
4778edf8e2afSMika Westerberg              *  Read in page from target process memory and
4779edf8e2afSMika Westerberg              *  write it to coredump file.
4780edf8e2afSMika Westerberg              */
4781edf8e2afSMika Westerberg             error = copy_from_user(page, addr, sizeof (page));
4782edf8e2afSMika Westerberg             if (error != 0) {
478349995e17SAurelien Jarno                 (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
4784edf8e2afSMika Westerberg                                addr);
4785edf8e2afSMika Westerberg                 errno = -error;
4786edf8e2afSMika Westerberg                 goto out;
4787edf8e2afSMika Westerberg             }
4788edf8e2afSMika Westerberg             if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
4789edf8e2afSMika Westerberg                 goto out;
4790edf8e2afSMika Westerberg         }
4791edf8e2afSMika Westerberg     }
4792edf8e2afSMika Westerberg 
4793edf8e2afSMika Westerberg  out:
4794edf8e2afSMika Westerberg     free_note_info(&info);
4795edf8e2afSMika Westerberg     if (mm != NULL)
4796edf8e2afSMika Westerberg         vma_delete(mm);
4797edf8e2afSMika Westerberg     (void) close(fd);
4798edf8e2afSMika Westerberg 
4799edf8e2afSMika Westerberg     if (errno != 0)
4800edf8e2afSMika Westerberg         return (-errno);
4801edf8e2afSMika Westerberg     return (0);
4802edf8e2afSMika Westerberg }
4803edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
4804edf8e2afSMika Westerberg 
4805e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
4806e5fe0c52Spbrook {
4807e5fe0c52Spbrook     init_thread(regs, infop);
4808e5fe0c52Spbrook }
4809