xref: /qemu/linux-user/elfload.c (revision a9f495b93f1497ced94dbe51ebb733537e0fa1ab)
131e31b8aSbellard /* This is the Linux kernel elf-loading code, ported into user space */
2d39594e9SPeter Maydell #include "qemu/osdep.h"
3edf8e2afSMika Westerberg #include <sys/param.h>
431e31b8aSbellard 
5edf8e2afSMika Westerberg #include <sys/resource.h>
630ab9ef2SRichard Henderson #include <sys/shm.h>
731e31b8aSbellard 
83ef693a0Sbellard #include "qemu.h"
93b249d26SPeter Maydell #include "user-internals.h"
10db2af69dSRichard Henderson #include "signal-common.h"
113ad0a769SPeter Maydell #include "loader.h"
125423e6d3SPeter Maydell #include "user-mmap.h"
1376cad711SPaolo Bonzini #include "disas/disas.h"
14ce543844SPhilippe Mathieu-Daudé #include "qemu/bitops.h"
15f348b6d1SVeronia Bahaa #include "qemu/path.h"
16dc5e9ac7SMarkus Armbruster #include "qemu/queue.h"
17c6a2377fSRichard Henderson #include "qemu/guest-random.h"
186fd59449SRichard Henderson #include "qemu/units.h"
19ee947430SAlex Bennée #include "qemu/selfmap.h"
20370ed600SJamie Iles #include "qemu/lockable.h"
21c7f17e7bSRichard Henderson #include "qapi/error.h"
22cc37d98bSRichard Henderson #include "qemu/error-report.h"
23db2af69dSRichard Henderson #include "target_signal.h"
247c10cb38SIlya Leoshkevich #include "accel/tcg/debuginfo.h"
2531e31b8aSbellard 
26e58ffeb3Smalc #ifdef _ARCH_PPC64
27a6cc84f4Smalc #undef ARCH_DLINFO
28a6cc84f4Smalc #undef ELF_PLATFORM
29a6cc84f4Smalc #undef ELF_HWCAP
30ad6919dcSPeter Maydell #undef ELF_HWCAP2
31a6cc84f4Smalc #undef ELF_CLASS
32a6cc84f4Smalc #undef ELF_DATA
33a6cc84f4Smalc #undef ELF_ARCH
34a6cc84f4Smalc #endif
35a6cc84f4Smalc 
36c40f621aSRichard Henderson #ifndef TARGET_ARCH_HAS_SIGTRAMP_PAGE
37c40f621aSRichard Henderson #define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
38c40f621aSRichard Henderson #endif
39c40f621aSRichard Henderson 
40c40f621aSRichard Henderson typedef struct {
41c40f621aSRichard Henderson     const uint8_t *image;
42c40f621aSRichard Henderson     const uint32_t *relocs;
43c40f621aSRichard Henderson     unsigned image_size;
44c40f621aSRichard Henderson     unsigned reloc_count;
45c40f621aSRichard Henderson     unsigned sigreturn_ofs;
46c40f621aSRichard Henderson     unsigned rt_sigreturn_ofs;
47c40f621aSRichard Henderson } VdsoImageInfo;
48c40f621aSRichard Henderson 
49edf8e2afSMika Westerberg #define ELF_OSABI   ELFOSABI_SYSV
50edf8e2afSMika Westerberg 
51cb33da57Sblueswir1 /* from personality.h */
52cb33da57Sblueswir1 
53cb33da57Sblueswir1 /*
54cb33da57Sblueswir1  * Flags for bug emulation.
55cb33da57Sblueswir1  *
56cb33da57Sblueswir1  * These occupy the top three bytes.
57cb33da57Sblueswir1  */
58cb33da57Sblueswir1 enum {
59cb33da57Sblueswir1     ADDR_NO_RANDOMIZE = 0x0040000,      /* disable randomization of VA space */
60d97ef72eSRichard Henderson     FDPIC_FUNCPTRS =    0x0080000,      /* userspace function ptrs point to
61d97ef72eSRichard Henderson                                            descriptors (signal handling) */
62cb33da57Sblueswir1     MMAP_PAGE_ZERO =    0x0100000,
63cb33da57Sblueswir1     ADDR_COMPAT_LAYOUT = 0x0200000,
64cb33da57Sblueswir1     READ_IMPLIES_EXEC = 0x0400000,
65cb33da57Sblueswir1     ADDR_LIMIT_32BIT =  0x0800000,
66cb33da57Sblueswir1     SHORT_INODE =       0x1000000,
67cb33da57Sblueswir1     WHOLE_SECONDS =     0x2000000,
68cb33da57Sblueswir1     STICKY_TIMEOUTS =   0x4000000,
69cb33da57Sblueswir1     ADDR_LIMIT_3GB =    0x8000000,
70cb33da57Sblueswir1 };
71cb33da57Sblueswir1 
72cb33da57Sblueswir1 /*
73cb33da57Sblueswir1  * Personality types.
74cb33da57Sblueswir1  *
75cb33da57Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
76cb33da57Sblueswir1  * conflict with error returns.
77cb33da57Sblueswir1  */
78cb33da57Sblueswir1 enum {
79cb33da57Sblueswir1     PER_LINUX =         0x0000,
80cb33da57Sblueswir1     PER_LINUX_32BIT =   0x0000 | ADDR_LIMIT_32BIT,
81cb33da57Sblueswir1     PER_LINUX_FDPIC =   0x0000 | FDPIC_FUNCPTRS,
82cb33da57Sblueswir1     PER_SVR4 =          0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
83cb33da57Sblueswir1     PER_SVR3 =          0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
84d97ef72eSRichard Henderson     PER_SCOSVR3 =       0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE,
85cb33da57Sblueswir1     PER_OSR5 =          0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
86cb33da57Sblueswir1     PER_WYSEV386 =      0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
87cb33da57Sblueswir1     PER_ISCR4 =         0x0005 | STICKY_TIMEOUTS,
88cb33da57Sblueswir1     PER_BSD =           0x0006,
89cb33da57Sblueswir1     PER_SUNOS =         0x0006 | STICKY_TIMEOUTS,
90cb33da57Sblueswir1     PER_XENIX =         0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
91cb33da57Sblueswir1     PER_LINUX32 =       0x0008,
92cb33da57Sblueswir1     PER_LINUX32_3GB =   0x0008 | ADDR_LIMIT_3GB,
93cb33da57Sblueswir1     PER_IRIX32 =        0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
94cb33da57Sblueswir1     PER_IRIXN32 =       0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
95cb33da57Sblueswir1     PER_IRIX64 =        0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
96cb33da57Sblueswir1     PER_RISCOS =        0x000c,
97cb33da57Sblueswir1     PER_SOLARIS =       0x000d | STICKY_TIMEOUTS,
98cb33da57Sblueswir1     PER_UW7 =           0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
99cb33da57Sblueswir1     PER_OSF4 =          0x000f,                  /* OSF/1 v4 */
100cb33da57Sblueswir1     PER_HPUX =          0x0010,
101cb33da57Sblueswir1     PER_MASK =          0x00ff,
102cb33da57Sblueswir1 };
103cb33da57Sblueswir1 
104cb33da57Sblueswir1 /*
105cb33da57Sblueswir1  * Return the base personality without flags.
106cb33da57Sblueswir1  */
107cb33da57Sblueswir1 #define personality(pers)       (pers & PER_MASK)
108cb33da57Sblueswir1 
1093cb10cfaSChristophe Lyon int info_is_fdpic(struct image_info *info)
1103cb10cfaSChristophe Lyon {
1113cb10cfaSChristophe Lyon     return info->personality == PER_LINUX_FDPIC;
1123cb10cfaSChristophe Lyon }
1133cb10cfaSChristophe Lyon 
11483fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
11583fb7adfSbellard #ifndef MAP_DENYWRITE
11683fb7adfSbellard #define MAP_DENYWRITE 0
11783fb7adfSbellard #endif
11883fb7adfSbellard 
11983fb7adfSbellard /* should probably go in elf.h */
12083fb7adfSbellard #ifndef ELIBBAD
12183fb7adfSbellard #define ELIBBAD 80
12283fb7adfSbellard #endif
12383fb7adfSbellard 
124ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
12528490231SRichard Henderson #define ELF_DATA        ELFDATA2MSB
12628490231SRichard Henderson #else
12728490231SRichard Henderson #define ELF_DATA        ELFDATA2LSB
12828490231SRichard Henderson #endif
12928490231SRichard Henderson 
130a29f998dSPaolo Bonzini #ifdef TARGET_ABI_MIPSN32
131918fc54cSPaolo Bonzini typedef abi_ullong      target_elf_greg_t;
132918fc54cSPaolo Bonzini #define tswapreg(ptr)   tswap64(ptr)
133a29f998dSPaolo Bonzini #else
134a29f998dSPaolo Bonzini typedef abi_ulong       target_elf_greg_t;
135a29f998dSPaolo Bonzini #define tswapreg(ptr)   tswapal(ptr)
136a29f998dSPaolo Bonzini #endif
137a29f998dSPaolo Bonzini 
13821e807faSNathan Froyd #ifdef USE_UID16
1391ddd592fSPaolo Bonzini typedef abi_ushort      target_uid_t;
1401ddd592fSPaolo Bonzini typedef abi_ushort      target_gid_t;
14121e807faSNathan Froyd #else
142f8fd4fc4SPaolo Bonzini typedef abi_uint        target_uid_t;
143f8fd4fc4SPaolo Bonzini typedef abi_uint        target_gid_t;
14421e807faSNathan Froyd #endif
145f8fd4fc4SPaolo Bonzini typedef abi_int         target_pid_t;
14621e807faSNathan Froyd 
14730ac07d4Sbellard #ifdef TARGET_I386
14830ac07d4Sbellard 
14915338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
15015338fd7Sbellard 
15115338fd7Sbellard static uint32_t get_elf_hwcap(void)
15215338fd7Sbellard {
153a2247f8eSAndreas Färber     X86CPU *cpu = X86_CPU(thread_cpu);
154a2247f8eSAndreas Färber 
155a2247f8eSAndreas Färber     return cpu->env.features[FEAT_1_EDX];
15615338fd7Sbellard }
15715338fd7Sbellard 
15884409ddbSj_mayer #ifdef TARGET_X86_64
15984409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
16084409ddbSj_mayer #define ELF_ARCH       EM_X86_64
16184409ddbSj_mayer 
1629263ba84SRichard Henderson #define ELF_PLATFORM   "x86_64"
1639263ba84SRichard Henderson 
16484409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
16584409ddbSj_mayer {
16684409ddbSj_mayer     regs->rax = 0;
16784409ddbSj_mayer     regs->rsp = infop->start_stack;
16884409ddbSj_mayer     regs->rip = infop->entry;
16984409ddbSj_mayer }
17084409ddbSj_mayer 
1719edc5d79SMika Westerberg #define ELF_NREG    27
172c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
1739edc5d79SMika Westerberg 
1749edc5d79SMika Westerberg /*
1759edc5d79SMika Westerberg  * Note that ELF_NREG should be 29 as there should be place for
1769edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
1779edc5d79SMika Westerberg  * those.
1789edc5d79SMika Westerberg  *
1799edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
1809edc5d79SMika Westerberg  */
18105390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
1829edc5d79SMika Westerberg {
183030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[15]);
184030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[14]);
185030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[13]);
186030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[12]);
187030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EBP]);
188030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBX]);
189030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[11]);
190030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->regs[10]);
191030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->regs[9]);
192030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->regs[8]);
193030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->regs[R_EAX]);
194030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_ECX]);
195030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->regs[R_EDX]);
196030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->regs[R_ESI]);
197030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->regs[R_EDI]);
198030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_EAX]); /* XXX */
199030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->eip);
200030912e0SIlya Leoshkevich     (*regs)[17] = tswapreg(env->segs[R_CS].selector & 0xffff);
201030912e0SIlya Leoshkevich     (*regs)[18] = tswapreg(env->eflags);
202030912e0SIlya Leoshkevich     (*regs)[19] = tswapreg(env->regs[R_ESP]);
203030912e0SIlya Leoshkevich     (*regs)[20] = tswapreg(env->segs[R_SS].selector & 0xffff);
204030912e0SIlya Leoshkevich     (*regs)[21] = tswapreg(env->segs[R_FS].selector & 0xffff);
205030912e0SIlya Leoshkevich     (*regs)[22] = tswapreg(env->segs[R_GS].selector & 0xffff);
206030912e0SIlya Leoshkevich     (*regs)[23] = tswapreg(env->segs[R_DS].selector & 0xffff);
207030912e0SIlya Leoshkevich     (*regs)[24] = tswapreg(env->segs[R_ES].selector & 0xffff);
208030912e0SIlya Leoshkevich     (*regs)[25] = tswapreg(env->segs[R_FS].selector & 0xffff);
209030912e0SIlya Leoshkevich     (*regs)[26] = tswapreg(env->segs[R_GS].selector & 0xffff);
2109edc5d79SMika Westerberg }
2119edc5d79SMika Westerberg 
212d461b73eSRichard Henderson #if ULONG_MAX > UINT32_MAX
213d461b73eSRichard Henderson #define INIT_GUEST_COMMPAGE
214d461b73eSRichard Henderson static bool init_guest_commpage(void)
215d461b73eSRichard Henderson {
216d461b73eSRichard Henderson     /*
217d461b73eSRichard Henderson      * The vsyscall page is at a high negative address aka kernel space,
218d461b73eSRichard Henderson      * which means that we cannot actually allocate it with target_mmap.
219d461b73eSRichard Henderson      * We still should be able to use page_set_flags, unless the user
220d461b73eSRichard Henderson      * has specified -R reserved_va, which would trigger an assert().
221d461b73eSRichard Henderson      */
222d461b73eSRichard Henderson     if (reserved_va != 0 &&
22395059f9cSRichard Henderson         TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE - 1 > reserved_va) {
224d461b73eSRichard Henderson         error_report("Cannot allocate vsyscall page");
225d461b73eSRichard Henderson         exit(EXIT_FAILURE);
226d461b73eSRichard Henderson     }
227d461b73eSRichard Henderson     page_set_flags(TARGET_VSYSCALL_PAGE,
22849840a4aSRichard Henderson                    TARGET_VSYSCALL_PAGE | ~TARGET_PAGE_MASK,
229d461b73eSRichard Henderson                    PAGE_EXEC | PAGE_VALID);
230d461b73eSRichard Henderson     return true;
231d461b73eSRichard Henderson }
232d461b73eSRichard Henderson #endif
23384409ddbSj_mayer #else
23484409ddbSj_mayer 
23530ac07d4Sbellard /*
23630ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
23730ac07d4Sbellard  */
23830ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
23930ac07d4Sbellard 
24030ac07d4Sbellard /*
24130ac07d4Sbellard  * These are used to set parameters in the core dumps.
24230ac07d4Sbellard  */
24330ac07d4Sbellard #define ELF_CLASS       ELFCLASS32
24430ac07d4Sbellard #define ELF_ARCH        EM_386
24530ac07d4Sbellard 
2469263ba84SRichard Henderson #define ELF_PLATFORM get_elf_platform()
247872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
2489263ba84SRichard Henderson 
2499263ba84SRichard Henderson static const char *get_elf_platform(void)
2509263ba84SRichard Henderson {
2519263ba84SRichard Henderson     static char elf_platform[] = "i386";
2529263ba84SRichard Henderson     int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
2539263ba84SRichard Henderson     if (family > 6) {
2549263ba84SRichard Henderson         family = 6;
2559263ba84SRichard Henderson     }
2569263ba84SRichard Henderson     if (family >= 3) {
2579263ba84SRichard Henderson         elf_platform[1] = '0' + family;
2589263ba84SRichard Henderson     }
2599263ba84SRichard Henderson     return elf_platform;
2609263ba84SRichard Henderson }
2619263ba84SRichard Henderson 
262d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
263d97ef72eSRichard Henderson                                struct image_info *infop)
264e5fe0c52Spbrook {
265e5fe0c52Spbrook     regs->esp = infop->start_stack;
266e5fe0c52Spbrook     regs->eip = infop->entry;
267e5fe0c52Spbrook 
26830ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
26930ac07d4Sbellard        starts %edx contains a pointer to a function which might be
27030ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
27130ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
27230ac07d4Sbellard        that have been loaded before the code runs.
27330ac07d4Sbellard 
27430ac07d4Sbellard        A value of 0 tells we have no such handler.  */
275e5fe0c52Spbrook     regs->edx = 0;
276b346ff46Sbellard }
2779edc5d79SMika Westerberg 
2789edc5d79SMika Westerberg #define ELF_NREG    17
279c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
2809edc5d79SMika Westerberg 
2819edc5d79SMika Westerberg /*
2829edc5d79SMika Westerberg  * Note that ELF_NREG should be 19 as there should be place for
2839edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
2849edc5d79SMika Westerberg  * those.
2859edc5d79SMika Westerberg  *
2869edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
2879edc5d79SMika Westerberg  */
28805390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
2899edc5d79SMika Westerberg {
290030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[R_EBX]);
291030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[R_ECX]);
292030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[R_EDX]);
293030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[R_ESI]);
294030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EDI]);
295030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBP]);
296030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[R_EAX]);
297030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->segs[R_DS].selector & 0xffff);
298030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->segs[R_ES].selector & 0xffff);
299030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->segs[R_FS].selector & 0xffff);
300030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->segs[R_GS].selector & 0xffff);
301030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_EAX]); /* XXX */
302030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->eip);
303030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->segs[R_CS].selector & 0xffff);
304030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->eflags);
305030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_ESP]);
306030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->segs[R_SS].selector & 0xffff);
3079edc5d79SMika Westerberg }
308a1367443SRichard Henderson 
309a1367443SRichard Henderson /*
310a1367443SRichard Henderson  * i386 is the only target which supplies AT_SYSINFO for the vdso.
311a1367443SRichard Henderson  * All others only supply AT_SYSINFO_EHDR.
312a1367443SRichard Henderson  */
313a1367443SRichard Henderson #define DLINFO_ARCH_ITEMS (vdso_info != NULL)
314a1367443SRichard Henderson #define ARCH_DLINFO                                     \
315a1367443SRichard Henderson     do {                                                \
316a1367443SRichard Henderson         if (vdso_info) {                                \
317a1367443SRichard Henderson             NEW_AUX_ENT(AT_SYSINFO, vdso_info->entry);  \
318a1367443SRichard Henderson         }                                               \
319a1367443SRichard Henderson     } while (0)
320a1367443SRichard Henderson 
321a1367443SRichard Henderson #endif /* TARGET_X86_64 */
322b346ff46Sbellard 
3236b1a9d38SRichard Henderson #define VDSO_HEADER "vdso.c.inc"
3246b1a9d38SRichard Henderson 
3259edc5d79SMika Westerberg #define USE_ELF_CORE_DUMP
326b346ff46Sbellard #define ELF_EXEC_PAGESIZE       4096
327b346ff46Sbellard 
328a1367443SRichard Henderson #endif /* TARGET_I386 */
329b346ff46Sbellard 
330b346ff46Sbellard #ifdef TARGET_ARM
331b346ff46Sbellard 
33224e76ff0SPeter Maydell #ifndef TARGET_AARCH64
33324e76ff0SPeter Maydell /* 32 bit ARM definitions */
33424e76ff0SPeter Maydell 
335b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_ARM
336b346ff46Sbellard #define ELF_CLASS       ELFCLASS32
337872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
338b346ff46Sbellard 
339d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
340d97ef72eSRichard Henderson                                struct image_info *infop)
341b346ff46Sbellard {
342992f48a0Sblueswir1     abi_long stack = infop->start_stack;
343b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
34499033caeSAlexander Graf 
345167e4cdcSPeter Maydell     regs->uregs[16] = ARM_CPU_MODE_USR;
346167e4cdcSPeter Maydell     if (infop->entry & 1) {
347167e4cdcSPeter Maydell         regs->uregs[16] |= CPSR_T;
348167e4cdcSPeter Maydell     }
349167e4cdcSPeter Maydell     regs->uregs[15] = infop->entry & 0xfffffffe;
350167e4cdcSPeter Maydell     regs->uregs[13] = infop->start_stack;
3512f619698Sbellard     /* FIXME - what to for failure of get_user()? */
352167e4cdcSPeter Maydell     get_user_ual(regs->uregs[2], stack + 8); /* envp */
353167e4cdcSPeter Maydell     get_user_ual(regs->uregs[1], stack + 4); /* envp */
354a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
355167e4cdcSPeter Maydell     regs->uregs[0] = 0;
356e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
357863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
358167e4cdcSPeter Maydell     regs->uregs[10] = infop->start_data;
3593cb10cfaSChristophe Lyon 
3603cb10cfaSChristophe Lyon     /* Support ARM FDPIC.  */
3613cb10cfaSChristophe Lyon     if (info_is_fdpic(infop)) {
3623cb10cfaSChristophe Lyon         /* As described in the ABI document, r7 points to the loadmap info
3633cb10cfaSChristophe Lyon          * prepared by the kernel. If an interpreter is needed, r8 points
3643cb10cfaSChristophe Lyon          * to the interpreter loadmap and r9 points to the interpreter
3653cb10cfaSChristophe Lyon          * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
3663cb10cfaSChristophe Lyon          * r9 points to the main program PT_DYNAMIC info.
3673cb10cfaSChristophe Lyon          */
3683cb10cfaSChristophe Lyon         regs->uregs[7] = infop->loadmap_addr;
3693cb10cfaSChristophe Lyon         if (infop->interpreter_loadmap_addr) {
3703cb10cfaSChristophe Lyon             /* Executable is dynamically loaded.  */
3713cb10cfaSChristophe Lyon             regs->uregs[8] = infop->interpreter_loadmap_addr;
3723cb10cfaSChristophe Lyon             regs->uregs[9] = infop->interpreter_pt_dynamic_addr;
3733cb10cfaSChristophe Lyon         } else {
3743cb10cfaSChristophe Lyon             regs->uregs[8] = 0;
3753cb10cfaSChristophe Lyon             regs->uregs[9] = infop->pt_dynamic_addr;
3763cb10cfaSChristophe Lyon         }
3773cb10cfaSChristophe Lyon     }
378b346ff46Sbellard }
379b346ff46Sbellard 
380edf8e2afSMika Westerberg #define ELF_NREG    18
381c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
382edf8e2afSMika Westerberg 
38305390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUARMState *env)
384edf8e2afSMika Westerberg {
38586cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->regs[0]);
38686cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->regs[1]);
38786cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->regs[2]);
38886cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->regs[3]);
38986cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->regs[4]);
39086cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->regs[5]);
39186cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->regs[6]);
39286cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->regs[7]);
39386cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->regs[8]);
39486cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->regs[9]);
39586cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->regs[10]);
39686cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->regs[11]);
39786cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->regs[12]);
39886cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->regs[13]);
39986cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->regs[14]);
40086cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->regs[15]);
401edf8e2afSMika Westerberg 
40286cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(cpsr_read((CPUARMState *)env));
40386cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->regs[0]); /* XXX */
404edf8e2afSMika Westerberg }
405edf8e2afSMika Westerberg 
40630ac07d4Sbellard #define USE_ELF_CORE_DUMP
40730ac07d4Sbellard #define ELF_EXEC_PAGESIZE       4096
40830ac07d4Sbellard 
409afce2927Sbellard enum
410afce2927Sbellard {
411afce2927Sbellard     ARM_HWCAP_ARM_SWP       = 1 << 0,
412afce2927Sbellard     ARM_HWCAP_ARM_HALF      = 1 << 1,
413afce2927Sbellard     ARM_HWCAP_ARM_THUMB     = 1 << 2,
414afce2927Sbellard     ARM_HWCAP_ARM_26BIT     = 1 << 3,
415afce2927Sbellard     ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
416afce2927Sbellard     ARM_HWCAP_ARM_FPA       = 1 << 5,
417afce2927Sbellard     ARM_HWCAP_ARM_VFP       = 1 << 6,
418afce2927Sbellard     ARM_HWCAP_ARM_EDSP      = 1 << 7,
419cf6de34aSRiku Voipio     ARM_HWCAP_ARM_JAVA      = 1 << 8,
420cf6de34aSRiku Voipio     ARM_HWCAP_ARM_IWMMXT    = 1 << 9,
42143ce393eSPeter Maydell     ARM_HWCAP_ARM_CRUNCH    = 1 << 10,
42243ce393eSPeter Maydell     ARM_HWCAP_ARM_THUMBEE   = 1 << 11,
42343ce393eSPeter Maydell     ARM_HWCAP_ARM_NEON      = 1 << 12,
42443ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3     = 1 << 13,
42543ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3D16  = 1 << 14,
42624682654SPeter Maydell     ARM_HWCAP_ARM_TLS       = 1 << 15,
42724682654SPeter Maydell     ARM_HWCAP_ARM_VFPv4     = 1 << 16,
42824682654SPeter Maydell     ARM_HWCAP_ARM_IDIVA     = 1 << 17,
42924682654SPeter Maydell     ARM_HWCAP_ARM_IDIVT     = 1 << 18,
43024682654SPeter Maydell     ARM_HWCAP_ARM_VFPD32    = 1 << 19,
43124682654SPeter Maydell     ARM_HWCAP_ARM_LPAE      = 1 << 20,
43224682654SPeter Maydell     ARM_HWCAP_ARM_EVTSTRM   = 1 << 21,
43323d7f14dSPeter Maydell     ARM_HWCAP_ARM_FPHP      = 1 << 22,
43423d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDHP   = 1 << 23,
43523d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDDP   = 1 << 24,
43623d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDFHM  = 1 << 25,
43723d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDBF16 = 1 << 26,
43823d7f14dSPeter Maydell     ARM_HWCAP_ARM_I8MM      = 1 << 27,
439afce2927Sbellard };
440afce2927Sbellard 
441ad6919dcSPeter Maydell enum {
442ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_AES      = 1 << 0,
443ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_PMULL    = 1 << 1,
444ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA1     = 1 << 2,
445ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA2     = 1 << 3,
446ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_CRC32    = 1 << 4,
44723d7f14dSPeter Maydell     ARM_HWCAP2_ARM_SB       = 1 << 5,
44823d7f14dSPeter Maydell     ARM_HWCAP2_ARM_SSBS     = 1 << 6,
449ad6919dcSPeter Maydell };
450ad6919dcSPeter Maydell 
4516b1275ffSPeter Maydell /* The commpage only exists for 32 bit kernels */
4526b1275ffSPeter Maydell 
45366346fafSRichard Henderson #define HI_COMMPAGE (intptr_t)0xffff0f00u
454ee947430SAlex Bennée 
455ee947430SAlex Bennée static bool init_guest_commpage(void)
45697cc7560SDr. David Alan Gilbert {
457d713cf4dSPhilippe Mathieu-Daudé     ARMCPU *cpu = ARM_CPU(thread_cpu);
458d713cf4dSPhilippe Mathieu-Daudé     abi_ptr commpage;
459d713cf4dSPhilippe Mathieu-Daudé     void *want;
460d713cf4dSPhilippe Mathieu-Daudé     void *addr;
461d713cf4dSPhilippe Mathieu-Daudé 
462d713cf4dSPhilippe Mathieu-Daudé     /*
463d713cf4dSPhilippe Mathieu-Daudé      * M-profile allocates maximum of 2GB address space, so can never
464d713cf4dSPhilippe Mathieu-Daudé      * allocate the commpage.  Skip it.
465d713cf4dSPhilippe Mathieu-Daudé      */
466d713cf4dSPhilippe Mathieu-Daudé     if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
467d713cf4dSPhilippe Mathieu-Daudé         return true;
468d713cf4dSPhilippe Mathieu-Daudé     }
469d713cf4dSPhilippe Mathieu-Daudé 
470d713cf4dSPhilippe Mathieu-Daudé     commpage = HI_COMMPAGE & -qemu_host_page_size;
471d713cf4dSPhilippe Mathieu-Daudé     want = g2h_untagged(commpage);
472d713cf4dSPhilippe Mathieu-Daudé     addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
4735c3e87f3SAlex Bennée                 MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
47497cc7560SDr. David Alan Gilbert 
4756cda41daSRichard Henderson     if (addr == MAP_FAILED) {
476ee947430SAlex Bennée         perror("Allocating guest commpage");
477ee947430SAlex Bennée         exit(EXIT_FAILURE);
478ee947430SAlex Bennée     }
479ee947430SAlex Bennée     if (addr != want) {
480ee947430SAlex Bennée         return false;
481806d1021SMeador Inge     }
482806d1021SMeador Inge 
483ee947430SAlex Bennée     /* Set kernel helper versions; rest of page is 0.  */
4846cda41daSRichard Henderson     __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu));
48597cc7560SDr. David Alan Gilbert 
4866cda41daSRichard Henderson     if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
48797cc7560SDr. David Alan Gilbert         perror("Protecting guest commpage");
488ee947430SAlex Bennée         exit(EXIT_FAILURE);
48997cc7560SDr. David Alan Gilbert     }
4906cda41daSRichard Henderson 
4916cda41daSRichard Henderson     page_set_flags(commpage, commpage | ~qemu_host_page_mask,
4926cda41daSRichard Henderson                    PAGE_READ | PAGE_EXEC | PAGE_VALID);
493ee947430SAlex Bennée     return true;
49497cc7560SDr. David Alan Gilbert }
495adf050b1SBenoit Canet 
496adf050b1SBenoit Canet #define ELF_HWCAP get_elf_hwcap()
497ad6919dcSPeter Maydell #define ELF_HWCAP2 get_elf_hwcap2()
498adf050b1SBenoit Canet 
499a55b9e72SHelge Deller uint32_t get_elf_hwcap(void)
500adf050b1SBenoit Canet {
501a2247f8eSAndreas Färber     ARMCPU *cpu = ARM_CPU(thread_cpu);
502adf050b1SBenoit Canet     uint32_t hwcaps = 0;
503adf050b1SBenoit Canet 
504adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_SWP;
505adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_HALF;
506adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_THUMB;
507adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
508adf050b1SBenoit Canet 
509adf050b1SBenoit Canet     /* probe for the extra features */
510adf050b1SBenoit Canet #define GET_FEATURE(feat, hwcap) \
511a2247f8eSAndreas Färber     do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
512962fcbf2SRichard Henderson 
513962fcbf2SRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
514962fcbf2SRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
515962fcbf2SRichard Henderson 
51624682654SPeter Maydell     /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
51724682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
518adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
519adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
520adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
52124682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
522bfa8a370SRichard Henderson     GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
523873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
524873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
525bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP);
526bfa8a370SRichard Henderson 
527bfa8a370SRichard Henderson     if (cpu_isar_feature(aa32_fpsp_v3, cpu) ||
528bfa8a370SRichard Henderson         cpu_isar_feature(aa32_fpdp_v3, cpu)) {
529bfa8a370SRichard Henderson         hwcaps |= ARM_HWCAP_ARM_VFPv3;
530bfa8a370SRichard Henderson         if (cpu_isar_feature(aa32_simd_r32, cpu)) {
531bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPD32;
532bfa8a370SRichard Henderson         } else {
533bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPv3D16;
534bfa8a370SRichard Henderson         }
535bfa8a370SRichard Henderson     }
536bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4);
537429b7e01SPeter Maydell     /*
538429b7e01SPeter Maydell      * MVFR1.FPHP and .SIMDHP must be in sync, and QEMU uses the same
539429b7e01SPeter Maydell      * isar_feature function for both. The kernel reports them as two hwcaps.
540429b7e01SPeter Maydell      */
541429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_FPHP);
542429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_ASIMDHP);
543429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_dp, ARM_HWCAP_ARM_ASIMDDP);
544429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fhm, ARM_HWCAP_ARM_ASIMDFHM);
545429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_bf16, ARM_HWCAP_ARM_ASIMDBF16);
546429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_i8mm, ARM_HWCAP_ARM_I8MM);
547adf050b1SBenoit Canet 
548adf050b1SBenoit Canet     return hwcaps;
549adf050b1SBenoit Canet }
550afce2927Sbellard 
551a55b9e72SHelge Deller uint32_t get_elf_hwcap2(void)
552ad6919dcSPeter Maydell {
553ad6919dcSPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
554ad6919dcSPeter Maydell     uint32_t hwcaps = 0;
555ad6919dcSPeter Maydell 
556962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_aes, ARM_HWCAP2_ARM_AES);
557962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_pmull, ARM_HWCAP2_ARM_PMULL);
558962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha1, ARM_HWCAP2_ARM_SHA1);
559962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha2, ARM_HWCAP2_ARM_SHA2);
560962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_crc32, ARM_HWCAP2_ARM_CRC32);
561429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_sb, ARM_HWCAP2_ARM_SB);
562429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_ssbs, ARM_HWCAP2_ARM_SSBS);
563ad6919dcSPeter Maydell     return hwcaps;
564ad6919dcSPeter Maydell }
565ad6919dcSPeter Maydell 
566a55b9e72SHelge Deller const char *elf_hwcap_str(uint32_t bit)
567a55b9e72SHelge Deller {
568a55b9e72SHelge Deller     static const char *hwcap_str[] = {
569a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_SWP      )] = "swp",
570a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_HALF     )] = "half",
571a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_THUMB    )] = "thumb",
572a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_26BIT    )] = "26bit",
573a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_FAST_MULT)] = "fast_mult",
574a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_FPA      )] = "fpa",
575a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFP      )] = "vfp",
576a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_EDSP     )] = "edsp",
577a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_JAVA     )] = "java",
578a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IWMMXT   )] = "iwmmxt",
579a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_CRUNCH   )] = "crunch",
580a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_THUMBEE  )] = "thumbee",
581a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_NEON     )] = "neon",
582a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv3    )] = "vfpv3",
583a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv3D16 )] = "vfpv3d16",
584a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_TLS      )] = "tls",
585a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv4    )] = "vfpv4",
586a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IDIVA    )] = "idiva",
587a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IDIVT    )] = "idivt",
588a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPD32   )] = "vfpd32",
589a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_LPAE     )] = "lpae",
590a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_EVTSTRM  )] = "evtstrm",
59123d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_FPHP     )] = "fphp",
59223d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDHP  )] = "asimdhp",
59323d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDDP  )] = "asimddp",
59423d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDFHM )] = "asimdfhm",
59523d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDBF16)] = "asimdbf16",
59623d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_I8MM     )] = "i8mm",
597a55b9e72SHelge Deller     };
598a55b9e72SHelge Deller 
599a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
600a55b9e72SHelge Deller }
601a55b9e72SHelge Deller 
602a55b9e72SHelge Deller const char *elf_hwcap2_str(uint32_t bit)
603a55b9e72SHelge Deller {
604a55b9e72SHelge Deller     static const char *hwcap_str[] = {
605a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_AES  )] = "aes",
606a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_PMULL)] = "pmull",
607a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_SHA1 )] = "sha1",
608a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_SHA2 )] = "sha2",
609a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_CRC32)] = "crc32",
61023d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_ARM_SB   )] = "sb",
61123d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_ARM_SSBS )] = "ssbs",
612a55b9e72SHelge Deller     };
613a55b9e72SHelge Deller 
614a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
615a55b9e72SHelge Deller }
616a55b9e72SHelge Deller 
617ad6919dcSPeter Maydell #undef GET_FEATURE
618962fcbf2SRichard Henderson #undef GET_FEATURE_ID
619ad6919dcSPeter Maydell 
62013ec4ec3SRichard Henderson #define ELF_PLATFORM get_elf_platform()
62113ec4ec3SRichard Henderson 
62213ec4ec3SRichard Henderson static const char *get_elf_platform(void)
62313ec4ec3SRichard Henderson {
624b77af26eSRichard Henderson     CPUARMState *env = cpu_env(thread_cpu);
62513ec4ec3SRichard Henderson 
626ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
62713ec4ec3SRichard Henderson # define END  "b"
62813ec4ec3SRichard Henderson #else
62913ec4ec3SRichard Henderson # define END  "l"
63013ec4ec3SRichard Henderson #endif
63113ec4ec3SRichard Henderson 
63213ec4ec3SRichard Henderson     if (arm_feature(env, ARM_FEATURE_V8)) {
63313ec4ec3SRichard Henderson         return "v8" END;
63413ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V7)) {
63513ec4ec3SRichard Henderson         if (arm_feature(env, ARM_FEATURE_M)) {
63613ec4ec3SRichard Henderson             return "v7m" END;
63713ec4ec3SRichard Henderson         } else {
63813ec4ec3SRichard Henderson             return "v7" END;
63913ec4ec3SRichard Henderson         }
64013ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V6)) {
64113ec4ec3SRichard Henderson         return "v6" END;
64213ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V5)) {
64313ec4ec3SRichard Henderson         return "v5" END;
64413ec4ec3SRichard Henderson     } else {
64513ec4ec3SRichard Henderson         return "v4" END;
64613ec4ec3SRichard Henderson     }
64713ec4ec3SRichard Henderson 
64813ec4ec3SRichard Henderson #undef END
64913ec4ec3SRichard Henderson }
65013ec4ec3SRichard Henderson 
65124e76ff0SPeter Maydell #else
65224e76ff0SPeter Maydell /* 64 bit ARM definitions */
65324e76ff0SPeter Maydell 
654b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_AARCH64
65524e76ff0SPeter Maydell #define ELF_CLASS       ELFCLASS64
656ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
657e20e3ec9SRichard Henderson # define ELF_PLATFORM    "aarch64_be"
658e20e3ec9SRichard Henderson #else
65924e76ff0SPeter Maydell # define ELF_PLATFORM    "aarch64"
660e20e3ec9SRichard Henderson #endif
66124e76ff0SPeter Maydell 
66224e76ff0SPeter Maydell static inline void init_thread(struct target_pt_regs *regs,
66324e76ff0SPeter Maydell                                struct image_info *infop)
66424e76ff0SPeter Maydell {
66524e76ff0SPeter Maydell     abi_long stack = infop->start_stack;
66624e76ff0SPeter Maydell     memset(regs, 0, sizeof(*regs));
66724e76ff0SPeter Maydell 
66824e76ff0SPeter Maydell     regs->pc = infop->entry & ~0x3ULL;
66924e76ff0SPeter Maydell     regs->sp = stack;
67024e76ff0SPeter Maydell }
67124e76ff0SPeter Maydell 
67224e76ff0SPeter Maydell #define ELF_NREG    34
67324e76ff0SPeter Maydell typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
67424e76ff0SPeter Maydell 
67524e76ff0SPeter Maydell static void elf_core_copy_regs(target_elf_gregset_t *regs,
67624e76ff0SPeter Maydell                                const CPUARMState *env)
67724e76ff0SPeter Maydell {
67824e76ff0SPeter Maydell     int i;
67924e76ff0SPeter Maydell 
68024e76ff0SPeter Maydell     for (i = 0; i < 32; i++) {
68124e76ff0SPeter Maydell         (*regs)[i] = tswapreg(env->xregs[i]);
68224e76ff0SPeter Maydell     }
68324e76ff0SPeter Maydell     (*regs)[32] = tswapreg(env->pc);
68424e76ff0SPeter Maydell     (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env));
68524e76ff0SPeter Maydell }
68624e76ff0SPeter Maydell 
68724e76ff0SPeter Maydell #define USE_ELF_CORE_DUMP
68824e76ff0SPeter Maydell #define ELF_EXEC_PAGESIZE       4096
68924e76ff0SPeter Maydell 
69024e76ff0SPeter Maydell enum {
69124e76ff0SPeter Maydell     ARM_HWCAP_A64_FP            = 1 << 0,
69224e76ff0SPeter Maydell     ARM_HWCAP_A64_ASIMD         = 1 << 1,
69324e76ff0SPeter Maydell     ARM_HWCAP_A64_EVTSTRM       = 1 << 2,
69424e76ff0SPeter Maydell     ARM_HWCAP_A64_AES           = 1 << 3,
69524e76ff0SPeter Maydell     ARM_HWCAP_A64_PMULL         = 1 << 4,
69624e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA1          = 1 << 5,
69724e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA2          = 1 << 6,
69824e76ff0SPeter Maydell     ARM_HWCAP_A64_CRC32         = 1 << 7,
699955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ATOMICS       = 1 << 8,
700955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FPHP          = 1 << 9,
701955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDHP       = 1 << 10,
702955f56d4SArd Biesheuvel     ARM_HWCAP_A64_CPUID         = 1 << 11,
703955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDRDM      = 1 << 12,
704955f56d4SArd Biesheuvel     ARM_HWCAP_A64_JSCVT         = 1 << 13,
705955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FCMA          = 1 << 14,
706955f56d4SArd Biesheuvel     ARM_HWCAP_A64_LRCPC         = 1 << 15,
707955f56d4SArd Biesheuvel     ARM_HWCAP_A64_DCPOP         = 1 << 16,
708955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA3          = 1 << 17,
709955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM3           = 1 << 18,
710955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM4           = 1 << 19,
711955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDDP       = 1 << 20,
712955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA512        = 1 << 21,
713955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SVE           = 1 << 22,
7140083a1faSRichard Henderson     ARM_HWCAP_A64_ASIMDFHM      = 1 << 23,
7150083a1faSRichard Henderson     ARM_HWCAP_A64_DIT           = 1 << 24,
7160083a1faSRichard Henderson     ARM_HWCAP_A64_USCAT         = 1 << 25,
7170083a1faSRichard Henderson     ARM_HWCAP_A64_ILRCPC        = 1 << 26,
7180083a1faSRichard Henderson     ARM_HWCAP_A64_FLAGM         = 1 << 27,
7190083a1faSRichard Henderson     ARM_HWCAP_A64_SSBS          = 1 << 28,
7200083a1faSRichard Henderson     ARM_HWCAP_A64_SB            = 1 << 29,
7210083a1faSRichard Henderson     ARM_HWCAP_A64_PACA          = 1 << 30,
7220083a1faSRichard Henderson     ARM_HWCAP_A64_PACG          = 1UL << 31,
7232041df4aSRichard Henderson 
7242041df4aSRichard Henderson     ARM_HWCAP2_A64_DCPODP       = 1 << 0,
7252041df4aSRichard Henderson     ARM_HWCAP2_A64_SVE2         = 1 << 1,
7262041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEAES       = 1 << 2,
7272041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEPMULL     = 1 << 3,
7282041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEBITPERM   = 1 << 4,
7292041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESHA3      = 1 << 5,
7302041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESM4       = 1 << 6,
7312041df4aSRichard Henderson     ARM_HWCAP2_A64_FLAGM2       = 1 << 7,
7322041df4aSRichard Henderson     ARM_HWCAP2_A64_FRINT        = 1 << 8,
73368948d18SRichard Henderson     ARM_HWCAP2_A64_SVEI8MM      = 1 << 9,
73468948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF32MM     = 1 << 10,
73568948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF64MM     = 1 << 11,
73668948d18SRichard Henderson     ARM_HWCAP2_A64_SVEBF16      = 1 << 12,
73768948d18SRichard Henderson     ARM_HWCAP2_A64_I8MM         = 1 << 13,
73868948d18SRichard Henderson     ARM_HWCAP2_A64_BF16         = 1 << 14,
73968948d18SRichard Henderson     ARM_HWCAP2_A64_DGH          = 1 << 15,
74068948d18SRichard Henderson     ARM_HWCAP2_A64_RNG          = 1 << 16,
74168948d18SRichard Henderson     ARM_HWCAP2_A64_BTI          = 1 << 17,
74268948d18SRichard Henderson     ARM_HWCAP2_A64_MTE          = 1 << 18,
743f9982ceaSRichard Henderson     ARM_HWCAP2_A64_ECV          = 1 << 19,
744f9982ceaSRichard Henderson     ARM_HWCAP2_A64_AFP          = 1 << 20,
745f9982ceaSRichard Henderson     ARM_HWCAP2_A64_RPRES        = 1 << 21,
746f9982ceaSRichard Henderson     ARM_HWCAP2_A64_MTE3         = 1 << 22,
747f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME          = 1 << 23,
748f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I16I64   = 1 << 24,
749f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F64F64   = 1 << 25,
750f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I8I32    = 1 << 26,
751f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F16F32   = 1 << 27,
752f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_B16F32   = 1 << 28,
753f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F32F32   = 1 << 29,
754f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_FA64     = 1 << 30,
75523d7f14dSPeter Maydell     ARM_HWCAP2_A64_WFXT         = 1ULL << 31,
75623d7f14dSPeter Maydell     ARM_HWCAP2_A64_EBF16        = 1ULL << 32,
75723d7f14dSPeter Maydell     ARM_HWCAP2_A64_SVE_EBF16    = 1ULL << 33,
75823d7f14dSPeter Maydell     ARM_HWCAP2_A64_CSSC         = 1ULL << 34,
75923d7f14dSPeter Maydell     ARM_HWCAP2_A64_RPRFM        = 1ULL << 35,
76023d7f14dSPeter Maydell     ARM_HWCAP2_A64_SVE2P1       = 1ULL << 36,
76123d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME2         = 1ULL << 37,
76223d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME2P1       = 1ULL << 38,
76323d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_I16I32   = 1ULL << 39,
76423d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_BI32I32  = 1ULL << 40,
76523d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_B16B16   = 1ULL << 41,
76623d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_F16F16   = 1ULL << 42,
76723d7f14dSPeter Maydell     ARM_HWCAP2_A64_MOPS         = 1ULL << 43,
76823d7f14dSPeter Maydell     ARM_HWCAP2_A64_HBC          = 1ULL << 44,
76924e76ff0SPeter Maydell };
77024e76ff0SPeter Maydell 
77124e76ff0SPeter Maydell #define ELF_HWCAP   get_elf_hwcap()
7722041df4aSRichard Henderson #define ELF_HWCAP2  get_elf_hwcap2()
7732041df4aSRichard Henderson 
7742041df4aSRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
7752041df4aSRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
77624e76ff0SPeter Maydell 
777a55b9e72SHelge Deller uint32_t get_elf_hwcap(void)
77824e76ff0SPeter Maydell {
77924e76ff0SPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
78024e76ff0SPeter Maydell     uint32_t hwcaps = 0;
78124e76ff0SPeter Maydell 
78224e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_FP;
78324e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_ASIMD;
78437020ff1SAlex Bennée     hwcaps |= ARM_HWCAP_A64_CPUID;
78524e76ff0SPeter Maydell 
78624e76ff0SPeter Maydell     /* probe for the extra features */
787962fcbf2SRichard Henderson 
788962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES);
789962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL);
790962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha1, ARM_HWCAP_A64_SHA1);
791962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha256, ARM_HWCAP_A64_SHA2);
792962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha512, ARM_HWCAP_A64_SHA512);
793962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_crc32, ARM_HWCAP_A64_CRC32);
794962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha3, ARM_HWCAP_A64_SHA3);
795962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm3, ARM_HWCAP_A64_SM3);
796962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm4, ARM_HWCAP_A64_SM4);
7975763190fSRichard Henderson     GET_FEATURE_ID(aa64_fp16, ARM_HWCAP_A64_FPHP | ARM_HWCAP_A64_ASIMDHP);
798962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_atomics, ARM_HWCAP_A64_ATOMICS);
799962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_rdm, ARM_HWCAP_A64_ASIMDRDM);
800962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_dp, ARM_HWCAP_A64_ASIMDDP);
801962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA);
802cd208a1cSRichard Henderson     GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE);
80329d26ab2SRichard Henderson     GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG);
8041c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM);
8051c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
8069888bd1eSRichard Henderson     GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
807b89d9c98SRichard Henderson     GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
8080d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
8092677cf9fSPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
810a1229109SPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
811962fcbf2SRichard Henderson 
8122041df4aSRichard Henderson     return hwcaps;
8132041df4aSRichard Henderson }
8142041df4aSRichard Henderson 
815a55b9e72SHelge Deller uint32_t get_elf_hwcap2(void)
8162041df4aSRichard Henderson {
8172041df4aSRichard Henderson     ARMCPU *cpu = ARM_CPU(thread_cpu);
8182041df4aSRichard Henderson     uint32_t hwcaps = 0;
8192041df4aSRichard Henderson 
8200d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
821cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2, ARM_HWCAP2_A64_SVE2);
822cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_aes, ARM_HWCAP2_A64_SVEAES);
823cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_pmull128, ARM_HWCAP2_A64_SVEPMULL);
824cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_bitperm, ARM_HWCAP2_A64_SVEBITPERM);
825cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sha3, ARM_HWCAP2_A64_SVESHA3);
826cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sm4, ARM_HWCAP2_A64_SVESM4);
8272041df4aSRichard Henderson     GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
8282041df4aSRichard Henderson     GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
829cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_i8mm, ARM_HWCAP2_A64_SVEI8MM);
830cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f32mm, ARM_HWCAP2_A64_SVEF32MM);
831cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f64mm, ARM_HWCAP2_A64_SVEF64MM);
8326c47a905SRichard Henderson     GET_FEATURE_ID(aa64_sve_bf16, ARM_HWCAP2_A64_SVEBF16);
833cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_i8mm, ARM_HWCAP2_A64_I8MM);
8346c47a905SRichard Henderson     GET_FEATURE_ID(aa64_bf16, ARM_HWCAP2_A64_BF16);
83568948d18SRichard Henderson     GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG);
83668948d18SRichard Henderson     GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI);
83768948d18SRichard Henderson     GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE);
838f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme, (ARM_HWCAP2_A64_SME |
839f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F32F32 |
840f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_B16F32 |
841f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F16F32 |
842f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_I8I32));
843f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_f64f64, ARM_HWCAP2_A64_SME_F64F64);
844f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_i16i64, ARM_HWCAP2_A64_SME_I16I64);
845f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_fa64, ARM_HWCAP2_A64_SME_FA64);
8463039b090SPeter Maydell     GET_FEATURE_ID(aa64_hbc, ARM_HWCAP2_A64_HBC);
847706a92fbSPeter Maydell     GET_FEATURE_ID(aa64_mops, ARM_HWCAP2_A64_MOPS);
84824e76ff0SPeter Maydell 
84924e76ff0SPeter Maydell     return hwcaps;
85024e76ff0SPeter Maydell }
85124e76ff0SPeter Maydell 
852a55b9e72SHelge Deller const char *elf_hwcap_str(uint32_t bit)
853a55b9e72SHelge Deller {
854a55b9e72SHelge Deller     static const char *hwcap_str[] = {
855a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FP      )] = "fp",
856a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMD   )] = "asimd",
857a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_EVTSTRM )] = "evtstrm",
858a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_AES     )] = "aes",
859a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PMULL   )] = "pmull",
860a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA1    )] = "sha1",
861a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA2    )] = "sha2",
862a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_CRC32   )] = "crc32",
863a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ATOMICS )] = "atomics",
864a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FPHP    )] = "fphp",
865a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDHP )] = "asimdhp",
866a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_CPUID   )] = "cpuid",
867a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDRDM)] = "asimdrdm",
868a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_JSCVT   )] = "jscvt",
869a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FCMA    )] = "fcma",
870a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_LRCPC   )] = "lrcpc",
871a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_DCPOP   )] = "dcpop",
872a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA3    )] = "sha3",
873a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SM3     )] = "sm3",
874a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SM4     )] = "sm4",
875a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDDP )] = "asimddp",
876a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA512  )] = "sha512",
877a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SVE     )] = "sve",
878a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDFHM)] = "asimdfhm",
879a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_DIT     )] = "dit",
880a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_USCAT   )] = "uscat",
881a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ILRCPC  )] = "ilrcpc",
882a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FLAGM   )] = "flagm",
883a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SSBS    )] = "ssbs",
884a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SB      )] = "sb",
885a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PACA    )] = "paca",
886a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PACG    )] = "pacg",
887a55b9e72SHelge Deller     };
888a55b9e72SHelge Deller 
889a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
890a55b9e72SHelge Deller }
891a55b9e72SHelge Deller 
892a55b9e72SHelge Deller const char *elf_hwcap2_str(uint32_t bit)
893a55b9e72SHelge Deller {
894a55b9e72SHelge Deller     static const char *hwcap_str[] = {
895a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_DCPODP       )] = "dcpodp",
896a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVE2         )] = "sve2",
897a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEAES       )] = "sveaes",
898a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEPMULL     )] = "svepmull",
899a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEBITPERM   )] = "svebitperm",
900a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVESHA3      )] = "svesha3",
901a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVESM4       )] = "svesm4",
902a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_FLAGM2       )] = "flagm2",
903a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_FRINT        )] = "frint",
904a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEI8MM      )] = "svei8mm",
905a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEF32MM     )] = "svef32mm",
906a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEF64MM     )] = "svef64mm",
907a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEBF16      )] = "svebf16",
908a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_I8MM         )] = "i8mm",
909a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_BF16         )] = "bf16",
910a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_DGH          )] = "dgh",
911a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_RNG          )] = "rng",
912a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_BTI          )] = "bti",
913a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_MTE          )] = "mte",
914a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_ECV          )] = "ecv",
915a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_AFP          )] = "afp",
916a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_RPRES        )] = "rpres",
917a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_MTE3         )] = "mte3",
918a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SME          )] = "sme",
919e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_I16I64   )] = "smei16i64",
920e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F64F64   )] = "smef64f64",
921e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_I8I32    )] = "smei8i32",
922e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F16F32   )] = "smef16f32",
923e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_B16F32   )] = "smeb16f32",
924e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F32F32   )] = "smef32f32",
925e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_FA64     )] = "smefa64",
92623d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_WFXT         )] = "wfxt",
92723d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_EBF16      )] = "ebf16",
92823d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SVE_EBF16  )] = "sveebf16",
92923d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_CSSC       )] = "cssc",
93023d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_RPRFM      )] = "rprfm",
93123d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SVE2P1     )] = "sve2p1",
93223d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME2       )] = "sme2",
93323d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME2P1     )] = "sme2p1",
93423d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_I16I32 )] = "smei16i32",
93523d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_BI32I32)] = "smebi32i32",
93623d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_B16B16 )] = "smeb16b16",
93723d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_F16F16 )] = "smef16f16",
93823d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_MOPS       )] = "mops",
93923d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_HBC        )] = "hbc",
940a55b9e72SHelge Deller     };
941a55b9e72SHelge Deller 
942a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
943a55b9e72SHelge Deller }
944a55b9e72SHelge Deller 
9452041df4aSRichard Henderson #undef GET_FEATURE_ID
9462041df4aSRichard Henderson 
947*a9f495b9SRichard Henderson #endif /* not TARGET_AARCH64 */
948*a9f495b9SRichard Henderson 
949ee95fae0SRichard Henderson #if TARGET_BIG_ENDIAN
950ee95fae0SRichard Henderson # define VDSO_HEADER  "vdso-be.c.inc"
951ee95fae0SRichard Henderson #else
952ee95fae0SRichard Henderson # define VDSO_HEADER  "vdso-le.c.inc"
953ee95fae0SRichard Henderson #endif
954ee95fae0SRichard Henderson 
95524e76ff0SPeter Maydell #endif /* TARGET_ARM */
95630ac07d4Sbellard 
957853d6f7aSbellard #ifdef TARGET_SPARC
958a315a145Sbellard #ifdef TARGET_SPARC64
959853d6f7aSbellard 
960cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
961cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV | HWCAP_SPARC_V9)
962992f48a0Sblueswir1 #ifndef TARGET_ABI32
963cb33da57Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
964992f48a0Sblueswir1 #else
965992f48a0Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
966992f48a0Sblueswir1 #endif
967853d6f7aSbellard 
968a315a145Sbellard #define ELF_CLASS   ELFCLASS64
9695ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
970a315a145Sbellard #else
971cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
972cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV)
973853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
974853d6f7aSbellard #define ELF_ARCH    EM_SPARC
975089a2256SRichard Henderson #endif /* TARGET_SPARC64 */
976853d6f7aSbellard 
977d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
978d97ef72eSRichard Henderson                                struct image_info *infop)
979853d6f7aSbellard {
980089a2256SRichard Henderson     /* Note that target_cpu_copy_regs does not read psr/tstate. */
981f5155289Sbellard     regs->pc = infop->entry;
982f5155289Sbellard     regs->npc = regs->pc + 4;
983f5155289Sbellard     regs->y = 0;
984089a2256SRichard Henderson     regs->u_regs[14] = (infop->start_stack - 16 * sizeof(abi_ulong)
985089a2256SRichard Henderson                         - TARGET_STACK_BIAS);
986853d6f7aSbellard }
987089a2256SRichard Henderson #endif /* TARGET_SPARC */
988853d6f7aSbellard 
98967867308Sbellard #ifdef TARGET_PPC
99067867308Sbellard 
9914ecd4d16SPeter Crosthwaite #define ELF_MACHINE    PPC_ELF_MACHINE
99267867308Sbellard 
99374154d7eSThomas Huth #if defined(TARGET_PPC64)
99484409ddbSj_mayer 
99584409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
99684409ddbSj_mayer 
99784409ddbSj_mayer #define ELF_CLASS       ELFCLASS64
99884409ddbSj_mayer 
99984409ddbSj_mayer #else
100084409ddbSj_mayer 
100167867308Sbellard #define ELF_CLASS       ELFCLASS32
1002872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
100384409ddbSj_mayer 
100484409ddbSj_mayer #endif
100584409ddbSj_mayer 
100667867308Sbellard #define ELF_ARCH        EM_PPC
100767867308Sbellard 
1008df84e4f3SNathan Froyd /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
1009df84e4f3SNathan Froyd    See arch/powerpc/include/asm/cputable.h.  */
1010df84e4f3SNathan Froyd enum {
10113efa9a67Smalc     QEMU_PPC_FEATURE_32 = 0x80000000,
10123efa9a67Smalc     QEMU_PPC_FEATURE_64 = 0x40000000,
10133efa9a67Smalc     QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
10143efa9a67Smalc     QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
10153efa9a67Smalc     QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
10163efa9a67Smalc     QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
10173efa9a67Smalc     QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
10183efa9a67Smalc     QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
10193efa9a67Smalc     QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
10203efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
10213efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
10223efa9a67Smalc     QEMU_PPC_FEATURE_NO_TB = 0x00100000,
10233efa9a67Smalc     QEMU_PPC_FEATURE_POWER4 = 0x00080000,
10243efa9a67Smalc     QEMU_PPC_FEATURE_POWER5 = 0x00040000,
10253efa9a67Smalc     QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
10263efa9a67Smalc     QEMU_PPC_FEATURE_CELL = 0x00010000,
10273efa9a67Smalc     QEMU_PPC_FEATURE_BOOKE = 0x00008000,
10283efa9a67Smalc     QEMU_PPC_FEATURE_SMT = 0x00004000,
10293efa9a67Smalc     QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
10303efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
10313efa9a67Smalc     QEMU_PPC_FEATURE_PA6T = 0x00000800,
10323efa9a67Smalc     QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
10333efa9a67Smalc     QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
10343efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
10353efa9a67Smalc     QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
10363efa9a67Smalc     QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
1037df84e4f3SNathan Froyd 
10383efa9a67Smalc     QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
10393efa9a67Smalc     QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
1040a60438ddSTom Musta 
1041a60438ddSTom Musta     /* Feature definitions in AT_HWCAP2.  */
1042a60438ddSTom Musta     QEMU_PPC_FEATURE2_ARCH_2_07 = 0x80000000, /* ISA 2.07 */
1043a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_HTM = 0x40000000, /* Hardware Transactional Memory */
1044a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_DSCR = 0x20000000, /* Data Stream Control Register */
1045a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */
1046a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */
1047a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */
104824c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_VEC_CRYPTO = 0x02000000,
104924c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NOSC = 0x01000000,
1050be0c46d4SSandipan Das     QEMU_PPC_FEATURE2_ARCH_3_00 = 0x00800000, /* ISA 3.00 */
105124c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HAS_IEEE128 = 0x00400000, /* VSX IEEE Bin Float 128-bit */
105224c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */
105324c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */
105424c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */
105596c343ccSJoel Stanley     QEMU_PPC_FEATURE2_ARCH_3_1 = 0x00040000, /* ISA 3.1 */
105696c343ccSJoel Stanley     QEMU_PPC_FEATURE2_MMA = 0x00020000, /* Matrix-Multiply Assist */
1057df84e4f3SNathan Froyd };
1058df84e4f3SNathan Froyd 
1059df84e4f3SNathan Froyd #define ELF_HWCAP get_elf_hwcap()
1060df84e4f3SNathan Froyd 
1061df84e4f3SNathan Froyd static uint32_t get_elf_hwcap(void)
1062df84e4f3SNathan Froyd {
1063a2247f8eSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
1064df84e4f3SNathan Froyd     uint32_t features = 0;
1065df84e4f3SNathan Froyd 
1066df84e4f3SNathan Froyd     /* We don't have to be terribly complete here; the high points are
1067df84e4f3SNathan Froyd        Altivec/FP/SPE support.  Anything else is just a bonus.  */
1068df84e4f3SNathan Froyd #define GET_FEATURE(flag, feature)                                      \
1069a2247f8eSAndreas Färber     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
107058eb5308SMichael Walle #define GET_FEATURE2(flags, feature) \
107158eb5308SMichael Walle     do { \
107258eb5308SMichael Walle         if ((cpu->env.insns_flags2 & flags) == flags) { \
107358eb5308SMichael Walle             features |= feature; \
107458eb5308SMichael Walle         } \
107558eb5308SMichael Walle     } while (0)
10763efa9a67Smalc     GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
10773efa9a67Smalc     GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
10783efa9a67Smalc     GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
10793efa9a67Smalc     GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
10803efa9a67Smalc     GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
10813efa9a67Smalc     GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
10823efa9a67Smalc     GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
10833efa9a67Smalc     GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
10840e019746STom Musta     GET_FEATURE2(PPC2_DFP, QEMU_PPC_FEATURE_HAS_DFP);
10850e019746STom Musta     GET_FEATURE2(PPC2_VSX, QEMU_PPC_FEATURE_HAS_VSX);
10860e019746STom Musta     GET_FEATURE2((PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 |
10870e019746STom Musta                   PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206),
10880e019746STom Musta                   QEMU_PPC_FEATURE_ARCH_2_06);
1089df84e4f3SNathan Froyd #undef GET_FEATURE
10900e019746STom Musta #undef GET_FEATURE2
1091df84e4f3SNathan Froyd 
1092df84e4f3SNathan Froyd     return features;
1093df84e4f3SNathan Froyd }
1094df84e4f3SNathan Froyd 
1095a60438ddSTom Musta #define ELF_HWCAP2 get_elf_hwcap2()
1096a60438ddSTom Musta 
1097a60438ddSTom Musta static uint32_t get_elf_hwcap2(void)
1098a60438ddSTom Musta {
1099a60438ddSTom Musta     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
1100a60438ddSTom Musta     uint32_t features = 0;
1101a60438ddSTom Musta 
1102a60438ddSTom Musta #define GET_FEATURE(flag, feature)                                      \
1103a60438ddSTom Musta     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
1104a60438ddSTom Musta #define GET_FEATURE2(flag, feature)                                      \
1105a60438ddSTom Musta     do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
1106a60438ddSTom Musta 
1107a60438ddSTom Musta     GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL);
1108a60438ddSTom Musta     GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR);
1109a60438ddSTom Musta     GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
111024c373ecSLaurent Vivier                   PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07 |
111124c373ecSLaurent Vivier                   QEMU_PPC_FEATURE2_VEC_CRYPTO);
111224c373ecSLaurent Vivier     GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 |
11138a589aebSKhem Raj                  QEMU_PPC_FEATURE2_DARN | QEMU_PPC_FEATURE2_HAS_IEEE128);
111496c343ccSJoel Stanley     GET_FEATURE2(PPC2_ISA310, QEMU_PPC_FEATURE2_ARCH_3_1 |
111596c343ccSJoel Stanley                  QEMU_PPC_FEATURE2_MMA);
1116a60438ddSTom Musta 
1117a60438ddSTom Musta #undef GET_FEATURE
1118a60438ddSTom Musta #undef GET_FEATURE2
1119a60438ddSTom Musta 
1120a60438ddSTom Musta     return features;
1121a60438ddSTom Musta }
1122a60438ddSTom Musta 
1123f5155289Sbellard /*
1124f5155289Sbellard  * The requirements here are:
1125f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
1126f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
1127f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
1128f5155289Sbellard  *   AT_IGNOREPPC is used for that.
1129f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
1130f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
1131f5155289Sbellard  */
11320bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
1133f5155289Sbellard #define ARCH_DLINFO                                     \
1134f5155289Sbellard     do {                                                \
1135623e250aSTom Musta         PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);              \
1136f5155289Sbellard         /*                                              \
113782991bedSPeter Maydell          * Handle glibc compatibility: these magic entries must \
113882991bedSPeter Maydell          * be at the lowest addresses in the final auxv.        \
1139f5155289Sbellard          */                                             \
11400bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
11410bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
114282991bedSPeter Maydell         NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
114382991bedSPeter Maydell         NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
114482991bedSPeter Maydell         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                 \
1145f5155289Sbellard     } while (0)
1146f5155289Sbellard 
114767867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
114867867308Sbellard {
114967867308Sbellard     _regs->gpr[1] = infop->start_stack;
115074154d7eSThomas Huth #if defined(TARGET_PPC64)
1151d90b94cdSDoug Kwan     if (get_ppc64_abi(infop) < 2) {
11522ccf97ecSPeter Maydell         uint64_t val;
11532ccf97ecSPeter Maydell         get_user_u64(val, infop->entry + 8);
11542ccf97ecSPeter Maydell         _regs->gpr[2] = val + infop->load_bias;
11552ccf97ecSPeter Maydell         get_user_u64(val, infop->entry);
11562ccf97ecSPeter Maydell         infop->entry = val + infop->load_bias;
1157d90b94cdSDoug Kwan     } else {
1158d90b94cdSDoug Kwan         _regs->gpr[12] = infop->entry;  /* r12 set to global entry address */
1159d90b94cdSDoug Kwan     }
116084409ddbSj_mayer #endif
116167867308Sbellard     _regs->nip = infop->entry;
116267867308Sbellard }
116367867308Sbellard 
1164e2f3e741SNathan Froyd /* See linux kernel: arch/powerpc/include/asm/elf.h.  */
1165e2f3e741SNathan Froyd #define ELF_NREG 48
1166e2f3e741SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1167e2f3e741SNathan Froyd 
116805390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *env)
1169e2f3e741SNathan Froyd {
1170e2f3e741SNathan Froyd     int i;
1171e2f3e741SNathan Froyd     target_ulong ccr = 0;
1172e2f3e741SNathan Froyd 
1173e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
117486cd7b2dSPaolo Bonzini         (*regs)[i] = tswapreg(env->gpr[i]);
1175e2f3e741SNathan Froyd     }
1176e2f3e741SNathan Froyd 
117786cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->nip);
117886cd7b2dSPaolo Bonzini     (*regs)[33] = tswapreg(env->msr);
117986cd7b2dSPaolo Bonzini     (*regs)[35] = tswapreg(env->ctr);
118086cd7b2dSPaolo Bonzini     (*regs)[36] = tswapreg(env->lr);
118110de0521SMatheus Ferst     (*regs)[37] = tswapreg(cpu_read_xer(env));
1182e2f3e741SNathan Froyd 
11832060436aSHarsh Prateek Bora     ccr = ppc_get_cr(env);
118486cd7b2dSPaolo Bonzini     (*regs)[38] = tswapreg(ccr);
1185e2f3e741SNathan Froyd }
1186e2f3e741SNathan Froyd 
1187e2f3e741SNathan Froyd #define USE_ELF_CORE_DUMP
118867867308Sbellard #define ELF_EXEC_PAGESIZE       4096
118967867308Sbellard 
119067867308Sbellard #endif
119167867308Sbellard 
11923418fe25SSong Gao #ifdef TARGET_LOONGARCH64
11933418fe25SSong Gao 
11943418fe25SSong Gao #define ELF_CLASS   ELFCLASS64
11953418fe25SSong Gao #define ELF_ARCH    EM_LOONGARCH
1196872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
11973418fe25SSong Gao 
11983418fe25SSong Gao #define elf_check_arch(x) ((x) == EM_LOONGARCH)
11993418fe25SSong Gao 
12003418fe25SSong Gao static inline void init_thread(struct target_pt_regs *regs,
12013418fe25SSong Gao                                struct image_info *infop)
12023418fe25SSong Gao {
12033418fe25SSong Gao     /*Set crmd PG,DA = 1,0 */
12043418fe25SSong Gao     regs->csr.crmd = 2 << 3;
12053418fe25SSong Gao     regs->csr.era = infop->entry;
12063418fe25SSong Gao     regs->regs[3] = infop->start_stack;
12073418fe25SSong Gao }
12083418fe25SSong Gao 
12093418fe25SSong Gao /* See linux kernel: arch/loongarch/include/asm/elf.h */
12103418fe25SSong Gao #define ELF_NREG 45
12113418fe25SSong Gao typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
12123418fe25SSong Gao 
12133418fe25SSong Gao enum {
12143418fe25SSong Gao     TARGET_EF_R0 = 0,
12153418fe25SSong Gao     TARGET_EF_CSR_ERA = TARGET_EF_R0 + 33,
12163418fe25SSong Gao     TARGET_EF_CSR_BADV = TARGET_EF_R0 + 34,
12173418fe25SSong Gao };
12183418fe25SSong Gao 
12193418fe25SSong Gao static void elf_core_copy_regs(target_elf_gregset_t *regs,
12203418fe25SSong Gao                                const CPULoongArchState *env)
12213418fe25SSong Gao {
12223418fe25SSong Gao     int i;
12233418fe25SSong Gao 
12243418fe25SSong Gao     (*regs)[TARGET_EF_R0] = 0;
12253418fe25SSong Gao 
12263418fe25SSong Gao     for (i = 1; i < ARRAY_SIZE(env->gpr); i++) {
12273418fe25SSong Gao         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->gpr[i]);
12283418fe25SSong Gao     }
12293418fe25SSong Gao 
12303418fe25SSong Gao     (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->pc);
12313418fe25SSong Gao     (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV);
12323418fe25SSong Gao }
12333418fe25SSong Gao 
12343418fe25SSong Gao #define USE_ELF_CORE_DUMP
12353418fe25SSong Gao #define ELF_EXEC_PAGESIZE        4096
12363418fe25SSong Gao 
12373418fe25SSong Gao #define ELF_HWCAP get_elf_hwcap()
12383418fe25SSong Gao 
12393418fe25SSong Gao /* See arch/loongarch/include/uapi/asm/hwcap.h */
12403418fe25SSong Gao enum {
12413418fe25SSong Gao     HWCAP_LOONGARCH_CPUCFG   = (1 << 0),
12423418fe25SSong Gao     HWCAP_LOONGARCH_LAM      = (1 << 1),
12433418fe25SSong Gao     HWCAP_LOONGARCH_UAL      = (1 << 2),
12443418fe25SSong Gao     HWCAP_LOONGARCH_FPU      = (1 << 3),
12453418fe25SSong Gao     HWCAP_LOONGARCH_LSX      = (1 << 4),
12463418fe25SSong Gao     HWCAP_LOONGARCH_LASX     = (1 << 5),
12473418fe25SSong Gao     HWCAP_LOONGARCH_CRC32    = (1 << 6),
12483418fe25SSong Gao     HWCAP_LOONGARCH_COMPLEX  = (1 << 7),
12493418fe25SSong Gao     HWCAP_LOONGARCH_CRYPTO   = (1 << 8),
12503418fe25SSong Gao     HWCAP_LOONGARCH_LVZ      = (1 << 9),
12513418fe25SSong Gao     HWCAP_LOONGARCH_LBT_X86  = (1 << 10),
12523418fe25SSong Gao     HWCAP_LOONGARCH_LBT_ARM  = (1 << 11),
12533418fe25SSong Gao     HWCAP_LOONGARCH_LBT_MIPS = (1 << 12),
12543418fe25SSong Gao };
12553418fe25SSong Gao 
12563418fe25SSong Gao static uint32_t get_elf_hwcap(void)
12573418fe25SSong Gao {
12583418fe25SSong Gao     LoongArchCPU *cpu = LOONGARCH_CPU(thread_cpu);
12593418fe25SSong Gao     uint32_t hwcaps = 0;
12603418fe25SSong Gao 
12613418fe25SSong Gao     hwcaps |= HWCAP_LOONGARCH_CRC32;
12623418fe25SSong Gao 
12633418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[1], CPUCFG1, UAL)) {
12643418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_UAL;
12653418fe25SSong Gao     }
12663418fe25SSong Gao 
12673418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, FP)) {
12683418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_FPU;
12693418fe25SSong Gao     }
12703418fe25SSong Gao 
12713418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LAM)) {
12723418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_LAM;
12733418fe25SSong Gao     }
12743418fe25SSong Gao 
1275a9f6004fSJiajie Chen     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
1276a9f6004fSJiajie Chen         hwcaps |= HWCAP_LOONGARCH_LSX;
1277a9f6004fSJiajie Chen     }
1278a9f6004fSJiajie Chen 
1279a9f6004fSJiajie Chen     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) {
1280a9f6004fSJiajie Chen         hwcaps |= HWCAP_LOONGARCH_LASX;
1281a9f6004fSJiajie Chen     }
1282a9f6004fSJiajie Chen 
12833418fe25SSong Gao     return hwcaps;
12843418fe25SSong Gao }
12853418fe25SSong Gao 
12863418fe25SSong Gao #define ELF_PLATFORM "loongarch"
12873418fe25SSong Gao 
12883418fe25SSong Gao #endif /* TARGET_LOONGARCH64 */
12893418fe25SSong Gao 
1290048f6b4dSbellard #ifdef TARGET_MIPS
1291048f6b4dSbellard 
1292388bb21aSths #ifdef TARGET_MIPS64
1293388bb21aSths #define ELF_CLASS   ELFCLASS64
1294388bb21aSths #else
1295048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
1296388bb21aSths #endif
1297048f6b4dSbellard #define ELF_ARCH    EM_MIPS
1298872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
1299048f6b4dSbellard 
1300ace3d654SCarlo Marcelo Arenas Belón #ifdef TARGET_ABI_MIPSN32
1301ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) ((x) & EF_MIPS_ABI2)
1302ace3d654SCarlo Marcelo Arenas Belón #else
1303ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (!((x) & EF_MIPS_ABI2))
1304ace3d654SCarlo Marcelo Arenas Belón #endif
1305ace3d654SCarlo Marcelo Arenas Belón 
1306fbf47c18SJiaxun Yang #define ELF_BASE_PLATFORM get_elf_base_platform()
1307fbf47c18SJiaxun Yang 
1308fbf47c18SJiaxun Yang #define MATCH_PLATFORM_INSN(_flags, _base_platform)      \
1309fbf47c18SJiaxun Yang     do { if ((cpu->env.insn_flags & (_flags)) == _flags) \
1310fbf47c18SJiaxun Yang     { return _base_platform; } } while (0)
1311fbf47c18SJiaxun Yang 
1312fbf47c18SJiaxun Yang static const char *get_elf_base_platform(void)
1313fbf47c18SJiaxun Yang {
1314fbf47c18SJiaxun Yang     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
1315fbf47c18SJiaxun Yang 
1316fbf47c18SJiaxun Yang     /* 64 bit ISAs goes first */
1317fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R6, "mips64r6");
1318fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R5, "mips64r5");
1319fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R2, "mips64r2");
1320fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R1, "mips64");
1321fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS5, "mips5");
1322fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS4, "mips4");
1323fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS3, "mips3");
1324fbf47c18SJiaxun Yang 
1325fbf47c18SJiaxun Yang     /* 32 bit ISAs */
1326fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R6, "mips32r6");
1327fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R5, "mips32r5");
1328fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R2, "mips32r2");
1329fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R1, "mips32");
1330fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS2, "mips2");
1331fbf47c18SJiaxun Yang 
1332fbf47c18SJiaxun Yang     /* Fallback */
1333fbf47c18SJiaxun Yang     return "mips";
1334fbf47c18SJiaxun Yang }
1335fbf47c18SJiaxun Yang #undef MATCH_PLATFORM_INSN
1336fbf47c18SJiaxun Yang 
1337d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1338d97ef72eSRichard Henderson                                struct image_info *infop)
1339048f6b4dSbellard {
1340623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
1341048f6b4dSbellard     regs->cp0_epc = infop->entry;
1342048f6b4dSbellard     regs->regs[29] = infop->start_stack;
1343048f6b4dSbellard }
1344048f6b4dSbellard 
134551e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/elf.h.  */
134651e52606SNathan Froyd #define ELF_NREG 45
134751e52606SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
134851e52606SNathan Froyd 
134951e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/reg.h.  */
135051e52606SNathan Froyd enum {
135151e52606SNathan Froyd #ifdef TARGET_MIPS64
135251e52606SNathan Froyd     TARGET_EF_R0 = 0,
135351e52606SNathan Froyd #else
135451e52606SNathan Froyd     TARGET_EF_R0 = 6,
135551e52606SNathan Froyd #endif
135651e52606SNathan Froyd     TARGET_EF_R26 = TARGET_EF_R0 + 26,
135751e52606SNathan Froyd     TARGET_EF_R27 = TARGET_EF_R0 + 27,
135851e52606SNathan Froyd     TARGET_EF_LO = TARGET_EF_R0 + 32,
135951e52606SNathan Froyd     TARGET_EF_HI = TARGET_EF_R0 + 33,
136051e52606SNathan Froyd     TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
136151e52606SNathan Froyd     TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
136251e52606SNathan Froyd     TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
136351e52606SNathan Froyd     TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
136451e52606SNathan Froyd };
136551e52606SNathan Froyd 
136651e52606SNathan Froyd /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
136705390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMIPSState *env)
136851e52606SNathan Froyd {
136951e52606SNathan Froyd     int i;
137051e52606SNathan Froyd 
137151e52606SNathan Froyd     for (i = 0; i < TARGET_EF_R0; i++) {
137251e52606SNathan Froyd         (*regs)[i] = 0;
137351e52606SNathan Froyd     }
137451e52606SNathan Froyd     (*regs)[TARGET_EF_R0] = 0;
137551e52606SNathan Froyd 
137651e52606SNathan Froyd     for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
1377a29f998dSPaolo Bonzini         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]);
137851e52606SNathan Froyd     }
137951e52606SNathan Froyd 
138051e52606SNathan Froyd     (*regs)[TARGET_EF_R26] = 0;
138151e52606SNathan Froyd     (*regs)[TARGET_EF_R27] = 0;
1382a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_LO] = tswapreg(env->active_tc.LO[0]);
1383a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_HI] = tswapreg(env->active_tc.HI[0]);
1384a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_EPC] = tswapreg(env->active_tc.PC);
1385a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_BADVADDR] = tswapreg(env->CP0_BadVAddr);
1386a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_STATUS] = tswapreg(env->CP0_Status);
1387a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_CAUSE] = tswapreg(env->CP0_Cause);
138851e52606SNathan Froyd }
138951e52606SNathan Froyd 
139051e52606SNathan Froyd #define USE_ELF_CORE_DUMP
1391388bb21aSths #define ELF_EXEC_PAGESIZE        4096
1392388bb21aSths 
139346a1ee4fSJames Cowgill /* See arch/mips/include/uapi/asm/hwcap.h.  */
139446a1ee4fSJames Cowgill enum {
139546a1ee4fSJames Cowgill     HWCAP_MIPS_R6           = (1 << 0),
139646a1ee4fSJames Cowgill     HWCAP_MIPS_MSA          = (1 << 1),
13979ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_CRC32        = (1 << 2),
13989ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16       = (1 << 3),
13999ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MDMX         = (1 << 4),
14009ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS3D       = (1 << 5),
14019ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_SMARTMIPS    = (1 << 6),
14029ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP          = (1 << 7),
14039ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP2         = (1 << 8),
14049ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP3         = (1 << 9),
14059ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16E2     = (1 << 10),
14069ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_MMI      = (1 << 11),
14079ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT      = (1 << 12),
14089ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT2     = (1 << 13),
14099ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_CPUCFG   = (1 << 14),
141046a1ee4fSJames Cowgill };
141146a1ee4fSJames Cowgill 
141246a1ee4fSJames Cowgill #define ELF_HWCAP get_elf_hwcap()
141346a1ee4fSJames Cowgill 
14147d9a3d96SPhilippe Mathieu-Daudé #define GET_FEATURE_INSN(_flag, _hwcap) \
14156dd97bfcSPhilippe Mathieu-Daudé     do { if (cpu->env.insn_flags & (_flag)) { hwcaps |= _hwcap; } } while (0)
14166dd97bfcSPhilippe Mathieu-Daudé 
1417388765a0SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_SET(_reg, _mask, _hwcap) \
1418388765a0SPhilippe Mathieu-Daudé     do { if (cpu->env._reg & (_mask)) { hwcaps |= _hwcap; } } while (0)
1419388765a0SPhilippe Mathieu-Daudé 
1420ce543844SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_EQU(_reg, _start, _length, _val, _hwcap) \
1421ce543844SPhilippe Mathieu-Daudé     do { \
1422ce543844SPhilippe Mathieu-Daudé         if (extract32(cpu->env._reg, (_start), (_length)) == (_val)) { \
1423ce543844SPhilippe Mathieu-Daudé             hwcaps |= _hwcap; \
1424ce543844SPhilippe Mathieu-Daudé         } \
1425ce543844SPhilippe Mathieu-Daudé     } while (0)
1426ce543844SPhilippe Mathieu-Daudé 
142746a1ee4fSJames Cowgill static uint32_t get_elf_hwcap(void)
142846a1ee4fSJames Cowgill {
142946a1ee4fSJames Cowgill     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
143046a1ee4fSJames Cowgill     uint32_t hwcaps = 0;
143146a1ee4fSJames Cowgill 
1432ce543844SPhilippe Mathieu-Daudé     GET_FEATURE_REG_EQU(CP0_Config0, CP0C0_AR, CP0C0_AR_LENGTH,
1433ce543844SPhilippe Mathieu-Daudé                         2, HWCAP_MIPS_R6);
1434388765a0SPhilippe Mathieu-Daudé     GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA);
143553673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LMMI, HWCAP_LOONGSON_MMI);
143653673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LEXT, HWCAP_LOONGSON_EXT);
143746a1ee4fSJames Cowgill 
143846a1ee4fSJames Cowgill     return hwcaps;
143946a1ee4fSJames Cowgill }
144046a1ee4fSJames Cowgill 
1441ce543844SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_EQU
1442388765a0SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_SET
14437d9a3d96SPhilippe Mathieu-Daudé #undef GET_FEATURE_INSN
14446dd97bfcSPhilippe Mathieu-Daudé 
1445048f6b4dSbellard #endif /* TARGET_MIPS */
1446048f6b4dSbellard 
1447b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
1448b779e29eSEdgar E. Iglesias 
14490d5d4699SEdgar E. Iglesias #define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
1450b779e29eSEdgar E. Iglesias 
1451b779e29eSEdgar E. Iglesias #define ELF_CLASS   ELFCLASS32
14520d5d4699SEdgar E. Iglesias #define ELF_ARCH    EM_MICROBLAZE
1453b779e29eSEdgar E. Iglesias 
1454d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1455d97ef72eSRichard Henderson                                struct image_info *infop)
1456b779e29eSEdgar E. Iglesias {
1457b779e29eSEdgar E. Iglesias     regs->pc = infop->entry;
1458b779e29eSEdgar E. Iglesias     regs->r1 = infop->start_stack;
1459b779e29eSEdgar E. Iglesias 
1460b779e29eSEdgar E. Iglesias }
1461b779e29eSEdgar E. Iglesias 
1462b779e29eSEdgar E. Iglesias #define ELF_EXEC_PAGESIZE        4096
1463b779e29eSEdgar E. Iglesias 
1464e4cbd44dSEdgar E. Iglesias #define USE_ELF_CORE_DUMP
1465e4cbd44dSEdgar E. Iglesias #define ELF_NREG 38
1466e4cbd44dSEdgar E. Iglesias typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1467e4cbd44dSEdgar E. Iglesias 
1468e4cbd44dSEdgar E. Iglesias /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
146905390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env)
1470e4cbd44dSEdgar E. Iglesias {
1471e4cbd44dSEdgar E. Iglesias     int i, pos = 0;
1472e4cbd44dSEdgar E. Iglesias 
1473e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 32; i++) {
147486cd7b2dSPaolo Bonzini         (*regs)[pos++] = tswapreg(env->regs[i]);
1475e4cbd44dSEdgar E. Iglesias     }
1476e4cbd44dSEdgar E. Iglesias 
1477af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->pc);
14781074c0fbSRichard Henderson     (*regs)[pos++] = tswapreg(mb_cpu_read_msr(env));
1479af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1480af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->ear);
1481af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1482af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->esr);
1483e4cbd44dSEdgar E. Iglesias }
1484e4cbd44dSEdgar E. Iglesias 
1485b779e29eSEdgar E. Iglesias #endif /* TARGET_MICROBLAZE */
1486b779e29eSEdgar E. Iglesias 
1487a0a839b6SMarek Vasut #ifdef TARGET_NIOS2
1488a0a839b6SMarek Vasut 
1489a0a839b6SMarek Vasut #define elf_check_arch(x) ((x) == EM_ALTERA_NIOS2)
1490a0a839b6SMarek Vasut 
1491a0a839b6SMarek Vasut #define ELF_CLASS   ELFCLASS32
1492a0a839b6SMarek Vasut #define ELF_ARCH    EM_ALTERA_NIOS2
1493a0a839b6SMarek Vasut 
1494a0a839b6SMarek Vasut static void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1495a0a839b6SMarek Vasut {
1496a0a839b6SMarek Vasut     regs->ea = infop->entry;
1497a0a839b6SMarek Vasut     regs->sp = infop->start_stack;
1498a0a839b6SMarek Vasut }
1499a0a839b6SMarek Vasut 
1500f5ef0e51SRichard Henderson #define LO_COMMPAGE  TARGET_PAGE_SIZE
1501f5ef0e51SRichard Henderson 
1502f5ef0e51SRichard Henderson static bool init_guest_commpage(void)
1503f5ef0e51SRichard Henderson {
1504f5ef0e51SRichard Henderson     static const uint8_t kuser_page[4 + 2 * 64] = {
1505f5ef0e51SRichard Henderson         /* __kuser_helper_version */
1506f5ef0e51SRichard Henderson         [0x00] = 0x02, 0x00, 0x00, 0x00,
1507f5ef0e51SRichard Henderson 
1508f5ef0e51SRichard Henderson         /* __kuser_cmpxchg */
1509f5ef0e51SRichard Henderson         [0x04] = 0x3a, 0x6c, 0x3b, 0x00,  /* trap 16 */
1510f5ef0e51SRichard Henderson                  0x3a, 0x28, 0x00, 0xf8,  /* ret */
1511f5ef0e51SRichard Henderson 
1512f5ef0e51SRichard Henderson         /* __kuser_sigtramp */
1513f5ef0e51SRichard Henderson         [0x44] = 0xc4, 0x22, 0x80, 0x00,  /* movi r2, __NR_rt_sigreturn */
1514f5ef0e51SRichard Henderson                  0x3a, 0x68, 0x3b, 0x00,  /* trap 0 */
1515f5ef0e51SRichard Henderson     };
1516f5ef0e51SRichard Henderson 
1517f5ef0e51SRichard Henderson     void *want = g2h_untagged(LO_COMMPAGE & -qemu_host_page_size);
1518f5ef0e51SRichard Henderson     void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
1519f5ef0e51SRichard Henderson                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1520f5ef0e51SRichard Henderson 
1521f5ef0e51SRichard Henderson     if (addr == MAP_FAILED) {
1522f5ef0e51SRichard Henderson         perror("Allocating guest commpage");
1523f5ef0e51SRichard Henderson         exit(EXIT_FAILURE);
1524f5ef0e51SRichard Henderson     }
1525f5ef0e51SRichard Henderson     if (addr != want) {
1526f5ef0e51SRichard Henderson         return false;
1527f5ef0e51SRichard Henderson     }
1528f5ef0e51SRichard Henderson 
1529f5ef0e51SRichard Henderson     memcpy(addr, kuser_page, sizeof(kuser_page));
1530f5ef0e51SRichard Henderson 
1531f5ef0e51SRichard Henderson     if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
1532f5ef0e51SRichard Henderson         perror("Protecting guest commpage");
1533f5ef0e51SRichard Henderson         exit(EXIT_FAILURE);
1534f5ef0e51SRichard Henderson     }
1535f5ef0e51SRichard Henderson 
153649840a4aSRichard Henderson     page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
1537f5ef0e51SRichard Henderson                    PAGE_READ | PAGE_EXEC | PAGE_VALID);
1538f5ef0e51SRichard Henderson     return true;
1539f5ef0e51SRichard Henderson }
1540f5ef0e51SRichard Henderson 
1541a0a839b6SMarek Vasut #define ELF_EXEC_PAGESIZE        4096
1542a0a839b6SMarek Vasut 
1543a0a839b6SMarek Vasut #define USE_ELF_CORE_DUMP
1544a0a839b6SMarek Vasut #define ELF_NREG 49
1545a0a839b6SMarek Vasut typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1546a0a839b6SMarek Vasut 
1547a0a839b6SMarek Vasut /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
1548a0a839b6SMarek Vasut static void elf_core_copy_regs(target_elf_gregset_t *regs,
1549a0a839b6SMarek Vasut                                const CPUNios2State *env)
1550a0a839b6SMarek Vasut {
1551a0a839b6SMarek Vasut     int i;
1552a0a839b6SMarek Vasut 
1553a0a839b6SMarek Vasut     (*regs)[0] = -1;
1554a0a839b6SMarek Vasut     for (i = 1; i < 8; i++)    /* r0-r7 */
1555a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1556a0a839b6SMarek Vasut 
1557a0a839b6SMarek Vasut     for (i = 8; i < 16; i++)   /* r8-r15 */
1558a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i - 8]);
1559a0a839b6SMarek Vasut 
1560a0a839b6SMarek Vasut     for (i = 16; i < 24; i++)  /* r16-r23 */
1561a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1562a0a839b6SMarek Vasut     (*regs)[24] = -1;    /* R_ET */
1563a0a839b6SMarek Vasut     (*regs)[25] = -1;    /* R_BT */
1564a0a839b6SMarek Vasut     (*regs)[26] = tswapreg(env->regs[R_GP]);
1565a0a839b6SMarek Vasut     (*regs)[27] = tswapreg(env->regs[R_SP]);
1566a0a839b6SMarek Vasut     (*regs)[28] = tswapreg(env->regs[R_FP]);
1567a0a839b6SMarek Vasut     (*regs)[29] = tswapreg(env->regs[R_EA]);
1568a0a839b6SMarek Vasut     (*regs)[30] = -1;    /* R_SSTATUS */
1569a0a839b6SMarek Vasut     (*regs)[31] = tswapreg(env->regs[R_RA]);
1570a0a839b6SMarek Vasut 
157117a406eeSRichard Henderson     (*regs)[32] = tswapreg(env->pc);
1572a0a839b6SMarek Vasut 
1573a0a839b6SMarek Vasut     (*regs)[33] = -1; /* R_STATUS */
1574a0a839b6SMarek Vasut     (*regs)[34] = tswapreg(env->regs[CR_ESTATUS]);
1575a0a839b6SMarek Vasut 
1576a0a839b6SMarek Vasut     for (i = 35; i < 49; i++)    /* ... */
1577a0a839b6SMarek Vasut         (*regs)[i] = -1;
1578a0a839b6SMarek Vasut }
1579a0a839b6SMarek Vasut 
1580a0a839b6SMarek Vasut #endif /* TARGET_NIOS2 */
1581a0a839b6SMarek Vasut 
1582d962783eSJia Liu #ifdef TARGET_OPENRISC
1583d962783eSJia Liu 
1584d962783eSJia Liu #define ELF_ARCH EM_OPENRISC
1585d962783eSJia Liu #define ELF_CLASS ELFCLASS32
1586d962783eSJia Liu #define ELF_DATA  ELFDATA2MSB
1587d962783eSJia Liu 
1588d962783eSJia Liu static inline void init_thread(struct target_pt_regs *regs,
1589d962783eSJia Liu                                struct image_info *infop)
1590d962783eSJia Liu {
1591d962783eSJia Liu     regs->pc = infop->entry;
1592d962783eSJia Liu     regs->gpr[1] = infop->start_stack;
1593d962783eSJia Liu }
1594d962783eSJia Liu 
1595d962783eSJia Liu #define USE_ELF_CORE_DUMP
1596d962783eSJia Liu #define ELF_EXEC_PAGESIZE 8192
1597d962783eSJia Liu 
1598d962783eSJia Liu /* See linux kernel arch/openrisc/include/asm/elf.h.  */
1599d962783eSJia Liu #define ELF_NREG 34 /* gprs and pc, sr */
1600d962783eSJia Liu typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1601d962783eSJia Liu 
1602d962783eSJia Liu static void elf_core_copy_regs(target_elf_gregset_t *regs,
1603d962783eSJia Liu                                const CPUOpenRISCState *env)
1604d962783eSJia Liu {
1605d962783eSJia Liu     int i;
1606d962783eSJia Liu 
1607d962783eSJia Liu     for (i = 0; i < 32; i++) {
1608d89e71e8SStafford Horne         (*regs)[i] = tswapreg(cpu_get_gpr(env, i));
1609d962783eSJia Liu     }
161086cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->pc);
161184775c43SRichard Henderson     (*regs)[33] = tswapreg(cpu_get_sr(env));
1612d962783eSJia Liu }
1613d962783eSJia Liu #define ELF_HWCAP 0
1614d962783eSJia Liu #define ELF_PLATFORM NULL
1615d962783eSJia Liu 
1616d962783eSJia Liu #endif /* TARGET_OPENRISC */
1617d962783eSJia Liu 
1618fdf9b3e8Sbellard #ifdef TARGET_SH4
1619fdf9b3e8Sbellard 
1620fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
1621fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
1622fdf9b3e8Sbellard 
1623d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1624d97ef72eSRichard Henderson                                struct image_info *infop)
1625fdf9b3e8Sbellard {
1626fdf9b3e8Sbellard     /* Check other registers XXXXX */
1627fdf9b3e8Sbellard     regs->pc = infop->entry;
1628072ae847Sths     regs->regs[15] = infop->start_stack;
1629fdf9b3e8Sbellard }
1630fdf9b3e8Sbellard 
16317631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/elf.h.  */
16327631c97eSNathan Froyd #define ELF_NREG 23
16337631c97eSNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
16347631c97eSNathan Froyd 
16357631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/ptrace.h.  */
16367631c97eSNathan Froyd enum {
16377631c97eSNathan Froyd     TARGET_REG_PC = 16,
16387631c97eSNathan Froyd     TARGET_REG_PR = 17,
16397631c97eSNathan Froyd     TARGET_REG_SR = 18,
16407631c97eSNathan Froyd     TARGET_REG_GBR = 19,
16417631c97eSNathan Froyd     TARGET_REG_MACH = 20,
16427631c97eSNathan Froyd     TARGET_REG_MACL = 21,
16437631c97eSNathan Froyd     TARGET_REG_SYSCALL = 22
16447631c97eSNathan Froyd };
16457631c97eSNathan Froyd 
1646d97ef72eSRichard Henderson static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
164705390248SAndreas Färber                                       const CPUSH4State *env)
16487631c97eSNathan Froyd {
16497631c97eSNathan Froyd     int i;
16507631c97eSNathan Froyd 
16517631c97eSNathan Froyd     for (i = 0; i < 16; i++) {
165272cd500bSPhilippe Mathieu-Daudé         (*regs)[i] = tswapreg(env->gregs[i]);
16537631c97eSNathan Froyd     }
16547631c97eSNathan Froyd 
165586cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
165686cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PR] = tswapreg(env->pr);
165786cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_SR] = tswapreg(env->sr);
165886cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_GBR] = tswapreg(env->gbr);
165986cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACH] = tswapreg(env->mach);
166086cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACL] = tswapreg(env->macl);
16617631c97eSNathan Froyd     (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
16627631c97eSNathan Froyd }
16637631c97eSNathan Froyd 
16647631c97eSNathan Froyd #define USE_ELF_CORE_DUMP
1665fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
1666fdf9b3e8Sbellard 
1667e42fd944SRichard Henderson enum {
1668e42fd944SRichard Henderson     SH_CPU_HAS_FPU            = 0x0001, /* Hardware FPU support */
1669e42fd944SRichard Henderson     SH_CPU_HAS_P2_FLUSH_BUG   = 0x0002, /* Need to flush the cache in P2 area */
1670e42fd944SRichard Henderson     SH_CPU_HAS_MMU_PAGE_ASSOC = 0x0004, /* SH3: TLB way selection bit support */
1671e42fd944SRichard Henderson     SH_CPU_HAS_DSP            = 0x0008, /* SH-DSP: DSP support */
1672e42fd944SRichard Henderson     SH_CPU_HAS_PERF_COUNTER   = 0x0010, /* Hardware performance counters */
1673e42fd944SRichard Henderson     SH_CPU_HAS_PTEA           = 0x0020, /* PTEA register */
1674e42fd944SRichard Henderson     SH_CPU_HAS_LLSC           = 0x0040, /* movli.l/movco.l */
1675e42fd944SRichard Henderson     SH_CPU_HAS_L2_CACHE       = 0x0080, /* Secondary cache / URAM */
1676e42fd944SRichard Henderson     SH_CPU_HAS_OP32           = 0x0100, /* 32-bit instruction support */
1677e42fd944SRichard Henderson     SH_CPU_HAS_PTEAEX         = 0x0200, /* PTE ASID Extension support */
1678e42fd944SRichard Henderson };
1679e42fd944SRichard Henderson 
1680e42fd944SRichard Henderson #define ELF_HWCAP get_elf_hwcap()
1681e42fd944SRichard Henderson 
1682e42fd944SRichard Henderson static uint32_t get_elf_hwcap(void)
1683e42fd944SRichard Henderson {
1684e42fd944SRichard Henderson     SuperHCPU *cpu = SUPERH_CPU(thread_cpu);
1685e42fd944SRichard Henderson     uint32_t hwcap = 0;
1686e42fd944SRichard Henderson 
1687e42fd944SRichard Henderson     hwcap |= SH_CPU_HAS_FPU;
1688e42fd944SRichard Henderson 
1689e42fd944SRichard Henderson     if (cpu->env.features & SH_FEATURE_SH4A) {
1690e42fd944SRichard Henderson         hwcap |= SH_CPU_HAS_LLSC;
1691e42fd944SRichard Henderson     }
1692e42fd944SRichard Henderson 
1693e42fd944SRichard Henderson     return hwcap;
1694e42fd944SRichard Henderson }
1695e42fd944SRichard Henderson 
1696fdf9b3e8Sbellard #endif
1697fdf9b3e8Sbellard 
169848733d19Sths #ifdef TARGET_CRIS
169948733d19Sths 
170048733d19Sths #define ELF_CLASS ELFCLASS32
170148733d19Sths #define ELF_ARCH  EM_CRIS
170248733d19Sths 
1703d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1704d97ef72eSRichard Henderson                                struct image_info *infop)
170548733d19Sths {
170648733d19Sths     regs->erp = infop->entry;
170748733d19Sths }
170848733d19Sths 
170948733d19Sths #define ELF_EXEC_PAGESIZE        8192
171048733d19Sths 
171148733d19Sths #endif
171248733d19Sths 
1713e6e5906bSpbrook #ifdef TARGET_M68K
1714e6e5906bSpbrook 
1715e6e5906bSpbrook #define ELF_CLASS       ELFCLASS32
1716e6e5906bSpbrook #define ELF_ARCH        EM_68K
1717e6e5906bSpbrook 
1718e6e5906bSpbrook /* ??? Does this need to do anything?
1719e6e5906bSpbrook    #define ELF_PLAT_INIT(_r) */
1720e6e5906bSpbrook 
1721d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1722d97ef72eSRichard Henderson                                struct image_info *infop)
1723e6e5906bSpbrook {
1724e6e5906bSpbrook     regs->usp = infop->start_stack;
1725e6e5906bSpbrook     regs->sr = 0;
1726e6e5906bSpbrook     regs->pc = infop->entry;
1727e6e5906bSpbrook }
1728e6e5906bSpbrook 
17297a93cc55SNathan Froyd /* See linux kernel: arch/m68k/include/asm/elf.h.  */
17307a93cc55SNathan Froyd #define ELF_NREG 20
17317a93cc55SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
17327a93cc55SNathan Froyd 
173305390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUM68KState *env)
17347a93cc55SNathan Froyd {
173586cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->dregs[1]);
173686cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->dregs[2]);
173786cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->dregs[3]);
173886cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->dregs[4]);
173986cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->dregs[5]);
174086cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->dregs[6]);
174186cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->dregs[7]);
174286cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->aregs[0]);
174386cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->aregs[1]);
174486cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->aregs[2]);
174586cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->aregs[3]);
174686cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->aregs[4]);
174786cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->aregs[5]);
174886cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->aregs[6]);
174986cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->dregs[0]);
175086cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->aregs[7]);
175186cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(env->dregs[0]); /* FIXME: orig_d0 */
175286cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->sr);
175386cd7b2dSPaolo Bonzini     (*regs)[18] = tswapreg(env->pc);
17547a93cc55SNathan Froyd     (*regs)[19] = 0;  /* FIXME: regs->format | regs->vector */
17557a93cc55SNathan Froyd }
17567a93cc55SNathan Froyd 
17577a93cc55SNathan Froyd #define USE_ELF_CORE_DUMP
1758e6e5906bSpbrook #define ELF_EXEC_PAGESIZE       8192
1759e6e5906bSpbrook 
1760e6e5906bSpbrook #endif
1761e6e5906bSpbrook 
17627a3148a9Sj_mayer #ifdef TARGET_ALPHA
17637a3148a9Sj_mayer 
17647a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
17657a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
17667a3148a9Sj_mayer 
1767d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1768d97ef72eSRichard Henderson                                struct image_info *infop)
17697a3148a9Sj_mayer {
17707a3148a9Sj_mayer     regs->pc = infop->entry;
17717a3148a9Sj_mayer     regs->ps = 8;
17727a3148a9Sj_mayer     regs->usp = infop->start_stack;
17737a3148a9Sj_mayer }
17747a3148a9Sj_mayer 
17757a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
17767a3148a9Sj_mayer 
17777a3148a9Sj_mayer #endif /* TARGET_ALPHA */
17787a3148a9Sj_mayer 
1779a4c075f1SUlrich Hecht #ifdef TARGET_S390X
1780a4c075f1SUlrich Hecht 
1781a4c075f1SUlrich Hecht #define ELF_CLASS	ELFCLASS64
1782a4c075f1SUlrich Hecht #define ELF_DATA	ELFDATA2MSB
1783a4c075f1SUlrich Hecht #define ELF_ARCH	EM_S390
1784a4c075f1SUlrich Hecht 
17856d88baf1SDavid Hildenbrand #include "elf.h"
17866d88baf1SDavid Hildenbrand 
17876d88baf1SDavid Hildenbrand #define ELF_HWCAP get_elf_hwcap()
17886d88baf1SDavid Hildenbrand 
17896d88baf1SDavid Hildenbrand #define GET_FEATURE(_feat, _hwcap) \
17906d88baf1SDavid Hildenbrand     do { if (s390_has_feat(_feat)) { hwcap |= _hwcap; } } while (0)
17916d88baf1SDavid Hildenbrand 
1792e1b819c8SIlya Leoshkevich uint32_t get_elf_hwcap(void)
17936d88baf1SDavid Hildenbrand {
17946d88baf1SDavid Hildenbrand     /*
17956d88baf1SDavid Hildenbrand      * Let's assume we always have esan3 and zarch.
17966d88baf1SDavid Hildenbrand      * 31-bit processes can use 64-bit registers (high gprs).
17976d88baf1SDavid Hildenbrand      */
17986d88baf1SDavid Hildenbrand     uint32_t hwcap = HWCAP_S390_ESAN3 | HWCAP_S390_ZARCH | HWCAP_S390_HIGH_GPRS;
17996d88baf1SDavid Hildenbrand 
18006d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_STFLE, HWCAP_S390_STFLE);
18016d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_MSA, HWCAP_S390_MSA);
18026d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_LONG_DISPLACEMENT, HWCAP_S390_LDISP);
18036d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_EXTENDED_IMMEDIATE, HWCAP_S390_EIMM);
18046d88baf1SDavid Hildenbrand     if (s390_has_feat(S390_FEAT_EXTENDED_TRANSLATION_3) &&
18056d88baf1SDavid Hildenbrand         s390_has_feat(S390_FEAT_ETF3_ENH)) {
18066d88baf1SDavid Hildenbrand         hwcap |= HWCAP_S390_ETF3EH;
18076d88baf1SDavid Hildenbrand     }
18086d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS);
1809da215c23SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR_ENH, HWCAP_S390_VXRS_EXT);
1810ffc8453bSIlya Leoshkevich     GET_FEATURE(S390_FEAT_VECTOR_ENH2, HWCAP_S390_VXRS_EXT2);
18116d88baf1SDavid Hildenbrand 
18126d88baf1SDavid Hildenbrand     return hwcap;
18136d88baf1SDavid Hildenbrand }
18146d88baf1SDavid Hildenbrand 
1815e19807beSIlya Leoshkevich const char *elf_hwcap_str(uint32_t bit)
1816e19807beSIlya Leoshkevich {
1817e19807beSIlya Leoshkevich     static const char *hwcap_str[] = {
18187f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ESAN3]     = "esan3",
18197f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ZARCH]     = "zarch",
18207f114a58SIlya Leoshkevich         [HWCAP_S390_NR_STFLE]     = "stfle",
18217f114a58SIlya Leoshkevich         [HWCAP_S390_NR_MSA]       = "msa",
18227f114a58SIlya Leoshkevich         [HWCAP_S390_NR_LDISP]     = "ldisp",
18237f114a58SIlya Leoshkevich         [HWCAP_S390_NR_EIMM]      = "eimm",
18247f114a58SIlya Leoshkevich         [HWCAP_S390_NR_DFP]       = "dfp",
18257f114a58SIlya Leoshkevich         [HWCAP_S390_NR_HPAGE]     = "edat",
18267f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ETF3EH]    = "etf3eh",
18277f114a58SIlya Leoshkevich         [HWCAP_S390_NR_HIGH_GPRS] = "highgprs",
18287f114a58SIlya Leoshkevich         [HWCAP_S390_NR_TE]        = "te",
18297f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS]      = "vx",
18307f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_BCD]  = "vxd",
18317f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_EXT]  = "vxe",
18327f114a58SIlya Leoshkevich         [HWCAP_S390_NR_GS]        = "gs",
18337f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_EXT2] = "vxe2",
18347f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_PDE]  = "vxp",
18357f114a58SIlya Leoshkevich         [HWCAP_S390_NR_SORT]      = "sort",
18367f114a58SIlya Leoshkevich         [HWCAP_S390_NR_DFLT]      = "dflt",
18377f114a58SIlya Leoshkevich         [HWCAP_S390_NR_NNPA]      = "nnpa",
18387f114a58SIlya Leoshkevich         [HWCAP_S390_NR_PCI_MIO]   = "pcimio",
18397f114a58SIlya Leoshkevich         [HWCAP_S390_NR_SIE]       = "sie",
1840e19807beSIlya Leoshkevich     };
1841e19807beSIlya Leoshkevich 
1842e19807beSIlya Leoshkevich     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
1843e19807beSIlya Leoshkevich }
1844e19807beSIlya Leoshkevich 
1845a4c075f1SUlrich Hecht static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1846a4c075f1SUlrich Hecht {
1847a4c075f1SUlrich Hecht     regs->psw.addr = infop->entry;
184878a1e153SIlya Leoshkevich     regs->psw.mask = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | \
184978a1e153SIlya Leoshkevich                      PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_MASK_64 | \
185078a1e153SIlya Leoshkevich                      PSW_MASK_32;
1851a4c075f1SUlrich Hecht     regs->gprs[15] = infop->start_stack;
1852a4c075f1SUlrich Hecht }
1853a4c075f1SUlrich Hecht 
18544a1e8931SIlya Leoshkevich /* See linux kernel: arch/s390/include/uapi/asm/ptrace.h (s390_regs).  */
18554a1e8931SIlya Leoshkevich #define ELF_NREG 27
18564a1e8931SIlya Leoshkevich typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
18574a1e8931SIlya Leoshkevich 
18584a1e8931SIlya Leoshkevich enum {
18594a1e8931SIlya Leoshkevich     TARGET_REG_PSWM = 0,
18604a1e8931SIlya Leoshkevich     TARGET_REG_PSWA = 1,
18614a1e8931SIlya Leoshkevich     TARGET_REG_GPRS = 2,
18624a1e8931SIlya Leoshkevich     TARGET_REG_ARS = 18,
18634a1e8931SIlya Leoshkevich     TARGET_REG_ORIG_R2 = 26,
18644a1e8931SIlya Leoshkevich };
18654a1e8931SIlya Leoshkevich 
18664a1e8931SIlya Leoshkevich static void elf_core_copy_regs(target_elf_gregset_t *regs,
18674a1e8931SIlya Leoshkevich                                const CPUS390XState *env)
18684a1e8931SIlya Leoshkevich {
18694a1e8931SIlya Leoshkevich     int i;
18704a1e8931SIlya Leoshkevich     uint32_t *aregs;
18714a1e8931SIlya Leoshkevich 
18724a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWM] = tswapreg(env->psw.mask);
18734a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWA] = tswapreg(env->psw.addr);
18744a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
18754a1e8931SIlya Leoshkevich         (*regs)[TARGET_REG_GPRS + i] = tswapreg(env->regs[i]);
18764a1e8931SIlya Leoshkevich     }
18774a1e8931SIlya Leoshkevich     aregs = (uint32_t *)&((*regs)[TARGET_REG_ARS]);
18784a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
18794a1e8931SIlya Leoshkevich         aregs[i] = tswap32(env->aregs[i]);
18804a1e8931SIlya Leoshkevich     }
18814a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_ORIG_R2] = 0;
18824a1e8931SIlya Leoshkevich }
18834a1e8931SIlya Leoshkevich 
18844a1e8931SIlya Leoshkevich #define USE_ELF_CORE_DUMP
18854a1e8931SIlya Leoshkevich #define ELF_EXEC_PAGESIZE 4096
18864a1e8931SIlya Leoshkevich 
1887a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
1888a4c075f1SUlrich Hecht 
188947ae93cdSMichael Clark #ifdef TARGET_RISCV
189047ae93cdSMichael Clark 
189147ae93cdSMichael Clark #define ELF_ARCH  EM_RISCV
189247ae93cdSMichael Clark 
189347ae93cdSMichael Clark #ifdef TARGET_RISCV32
189447ae93cdSMichael Clark #define ELF_CLASS ELFCLASS32
189547ae93cdSMichael Clark #else
189647ae93cdSMichael Clark #define ELF_CLASS ELFCLASS64
189747ae93cdSMichael Clark #endif
189847ae93cdSMichael Clark 
1899cb46938cSKito Cheng #define ELF_HWCAP get_elf_hwcap()
1900cb46938cSKito Cheng 
1901cb46938cSKito Cheng static uint32_t get_elf_hwcap(void)
1902cb46938cSKito Cheng {
1903cb46938cSKito Cheng #define MISA_BIT(EXT) (1 << (EXT - 'A'))
1904cb46938cSKito Cheng     RISCVCPU *cpu = RISCV_CPU(thread_cpu);
1905cb46938cSKito Cheng     uint32_t mask = MISA_BIT('I') | MISA_BIT('M') | MISA_BIT('A')
19064333f092SNathan Egge                     | MISA_BIT('F') | MISA_BIT('D') | MISA_BIT('C')
19074333f092SNathan Egge                     | MISA_BIT('V');
1908cb46938cSKito Cheng 
1909e91a7227SRichard Henderson     return cpu->env.misa_ext & mask;
1910cb46938cSKito Cheng #undef MISA_BIT
1911cb46938cSKito Cheng }
1912cb46938cSKito Cheng 
191347ae93cdSMichael Clark static inline void init_thread(struct target_pt_regs *regs,
191447ae93cdSMichael Clark                                struct image_info *infop)
191547ae93cdSMichael Clark {
191647ae93cdSMichael Clark     regs->sepc = infop->entry;
191747ae93cdSMichael Clark     regs->sp = infop->start_stack;
191847ae93cdSMichael Clark }
191947ae93cdSMichael Clark 
192047ae93cdSMichael Clark #define ELF_EXEC_PAGESIZE 4096
192147ae93cdSMichael Clark 
192247ae93cdSMichael Clark #endif /* TARGET_RISCV */
192347ae93cdSMichael Clark 
19247c248bcdSRichard Henderson #ifdef TARGET_HPPA
19257c248bcdSRichard Henderson 
19267c248bcdSRichard Henderson #define ELF_CLASS       ELFCLASS32
19277c248bcdSRichard Henderson #define ELF_ARCH        EM_PARISC
19287c248bcdSRichard Henderson #define ELF_PLATFORM    "PARISC"
19297c248bcdSRichard Henderson #define STACK_GROWS_DOWN 0
19307c248bcdSRichard Henderson #define STACK_ALIGNMENT  64
19317c248bcdSRichard Henderson 
19327c248bcdSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
19337c248bcdSRichard Henderson                                struct image_info *infop)
19347c248bcdSRichard Henderson {
19357c248bcdSRichard Henderson     regs->iaoq[0] = infop->entry;
19367c248bcdSRichard Henderson     regs->iaoq[1] = infop->entry + 4;
19377c248bcdSRichard Henderson     regs->gr[23] = 0;
193860f1c801SRichard Henderson     regs->gr[24] = infop->argv;
193960f1c801SRichard Henderson     regs->gr[25] = infop->argc;
19407c248bcdSRichard Henderson     /* The top-of-stack contains a linkage buffer.  */
19417c248bcdSRichard Henderson     regs->gr[30] = infop->start_stack + 64;
19427c248bcdSRichard Henderson     regs->gr[31] = infop->entry;
19437c248bcdSRichard Henderson }
19447c248bcdSRichard Henderson 
1945eee816c0SRichard Henderson #define LO_COMMPAGE  0
1946eee816c0SRichard Henderson 
1947eee816c0SRichard Henderson static bool init_guest_commpage(void)
1948eee816c0SRichard Henderson {
1949eee816c0SRichard Henderson     void *want = g2h_untagged(LO_COMMPAGE);
1950eee816c0SRichard Henderson     void *addr = mmap(want, qemu_host_page_size, PROT_NONE,
1951eee816c0SRichard Henderson                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1952eee816c0SRichard Henderson 
1953eee816c0SRichard Henderson     if (addr == MAP_FAILED) {
1954eee816c0SRichard Henderson         perror("Allocating guest commpage");
1955eee816c0SRichard Henderson         exit(EXIT_FAILURE);
1956eee816c0SRichard Henderson     }
1957eee816c0SRichard Henderson     if (addr != want) {
1958eee816c0SRichard Henderson         return false;
1959eee816c0SRichard Henderson     }
1960eee816c0SRichard Henderson 
1961eee816c0SRichard Henderson     /*
1962eee816c0SRichard Henderson      * On Linux, page zero is normally marked execute only + gateway.
1963eee816c0SRichard Henderson      * Normal read or write is supposed to fail (thus PROT_NONE above),
1964eee816c0SRichard Henderson      * but specific offsets have kernel code mapped to raise permissions
1965eee816c0SRichard Henderson      * and implement syscalls.  Here, simply mark the page executable.
1966eee816c0SRichard Henderson      * Special case the entry points during translation (see do_page_zero).
1967eee816c0SRichard Henderson      */
196849840a4aSRichard Henderson     page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
1969eee816c0SRichard Henderson                    PAGE_EXEC | PAGE_VALID);
1970eee816c0SRichard Henderson     return true;
1971eee816c0SRichard Henderson }
1972eee816c0SRichard Henderson 
19737c248bcdSRichard Henderson #endif /* TARGET_HPPA */
19747c248bcdSRichard Henderson 
1975ba7651fbSMax Filippov #ifdef TARGET_XTENSA
1976ba7651fbSMax Filippov 
1977ba7651fbSMax Filippov #define ELF_CLASS       ELFCLASS32
1978ba7651fbSMax Filippov #define ELF_ARCH        EM_XTENSA
1979ba7651fbSMax Filippov 
1980ba7651fbSMax Filippov static inline void init_thread(struct target_pt_regs *regs,
1981ba7651fbSMax Filippov                                struct image_info *infop)
1982ba7651fbSMax Filippov {
1983ba7651fbSMax Filippov     regs->windowbase = 0;
1984ba7651fbSMax Filippov     regs->windowstart = 1;
1985ba7651fbSMax Filippov     regs->areg[1] = infop->start_stack;
1986ba7651fbSMax Filippov     regs->pc = infop->entry;
1987d2796be6SMax Filippov     if (info_is_fdpic(infop)) {
1988d2796be6SMax Filippov         regs->areg[4] = infop->loadmap_addr;
1989d2796be6SMax Filippov         regs->areg[5] = infop->interpreter_loadmap_addr;
1990d2796be6SMax Filippov         if (infop->interpreter_loadmap_addr) {
1991d2796be6SMax Filippov             regs->areg[6] = infop->interpreter_pt_dynamic_addr;
1992d2796be6SMax Filippov         } else {
1993d2796be6SMax Filippov             regs->areg[6] = infop->pt_dynamic_addr;
1994d2796be6SMax Filippov         }
1995d2796be6SMax Filippov     }
1996ba7651fbSMax Filippov }
1997ba7651fbSMax Filippov 
1998ba7651fbSMax Filippov /* See linux kernel: arch/xtensa/include/asm/elf.h.  */
1999ba7651fbSMax Filippov #define ELF_NREG 128
2000ba7651fbSMax Filippov typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
2001ba7651fbSMax Filippov 
2002ba7651fbSMax Filippov enum {
2003ba7651fbSMax Filippov     TARGET_REG_PC,
2004ba7651fbSMax Filippov     TARGET_REG_PS,
2005ba7651fbSMax Filippov     TARGET_REG_LBEG,
2006ba7651fbSMax Filippov     TARGET_REG_LEND,
2007ba7651fbSMax Filippov     TARGET_REG_LCOUNT,
2008ba7651fbSMax Filippov     TARGET_REG_SAR,
2009ba7651fbSMax Filippov     TARGET_REG_WINDOWSTART,
2010ba7651fbSMax Filippov     TARGET_REG_WINDOWBASE,
2011ba7651fbSMax Filippov     TARGET_REG_THREADPTR,
2012ba7651fbSMax Filippov     TARGET_REG_AR0 = 64,
2013ba7651fbSMax Filippov };
2014ba7651fbSMax Filippov 
2015ba7651fbSMax Filippov static void elf_core_copy_regs(target_elf_gregset_t *regs,
2016ba7651fbSMax Filippov                                const CPUXtensaState *env)
2017ba7651fbSMax Filippov {
2018ba7651fbSMax Filippov     unsigned i;
2019ba7651fbSMax Filippov 
2020ba7651fbSMax Filippov     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
2021ba7651fbSMax Filippov     (*regs)[TARGET_REG_PS] = tswapreg(env->sregs[PS] & ~PS_EXCM);
2022ba7651fbSMax Filippov     (*regs)[TARGET_REG_LBEG] = tswapreg(env->sregs[LBEG]);
2023ba7651fbSMax Filippov     (*regs)[TARGET_REG_LEND] = tswapreg(env->sregs[LEND]);
2024ba7651fbSMax Filippov     (*regs)[TARGET_REG_LCOUNT] = tswapreg(env->sregs[LCOUNT]);
2025ba7651fbSMax Filippov     (*regs)[TARGET_REG_SAR] = tswapreg(env->sregs[SAR]);
2026ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWSTART] = tswapreg(env->sregs[WINDOW_START]);
2027ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWBASE] = tswapreg(env->sregs[WINDOW_BASE]);
2028ba7651fbSMax Filippov     (*regs)[TARGET_REG_THREADPTR] = tswapreg(env->uregs[THREADPTR]);
2029ba7651fbSMax Filippov     xtensa_sync_phys_from_window((CPUXtensaState *)env);
2030ba7651fbSMax Filippov     for (i = 0; i < env->config->nareg; ++i) {
2031ba7651fbSMax Filippov         (*regs)[TARGET_REG_AR0 + i] = tswapreg(env->phys_regs[i]);
2032ba7651fbSMax Filippov     }
2033ba7651fbSMax Filippov }
2034ba7651fbSMax Filippov 
2035ba7651fbSMax Filippov #define USE_ELF_CORE_DUMP
2036ba7651fbSMax Filippov #define ELF_EXEC_PAGESIZE       4096
2037ba7651fbSMax Filippov 
2038ba7651fbSMax Filippov #endif /* TARGET_XTENSA */
2039ba7651fbSMax Filippov 
2040d2a56bd2STaylor Simpson #ifdef TARGET_HEXAGON
2041d2a56bd2STaylor Simpson 
2042d2a56bd2STaylor Simpson #define ELF_CLASS       ELFCLASS32
2043d2a56bd2STaylor Simpson #define ELF_ARCH        EM_HEXAGON
2044d2a56bd2STaylor Simpson 
2045d2a56bd2STaylor Simpson static inline void init_thread(struct target_pt_regs *regs,
2046d2a56bd2STaylor Simpson                                struct image_info *infop)
2047d2a56bd2STaylor Simpson {
2048d2a56bd2STaylor Simpson     regs->sepc = infop->entry;
2049d2a56bd2STaylor Simpson     regs->sp = infop->start_stack;
2050d2a56bd2STaylor Simpson }
2051d2a56bd2STaylor Simpson 
2052d2a56bd2STaylor Simpson #endif /* TARGET_HEXAGON */
2053d2a56bd2STaylor Simpson 
2054fcdc0ab4SJiaxun Yang #ifndef ELF_BASE_PLATFORM
2055fcdc0ab4SJiaxun Yang #define ELF_BASE_PLATFORM (NULL)
2056fcdc0ab4SJiaxun Yang #endif
2057fcdc0ab4SJiaxun Yang 
205815338fd7Sbellard #ifndef ELF_PLATFORM
205915338fd7Sbellard #define ELF_PLATFORM (NULL)
206015338fd7Sbellard #endif
206115338fd7Sbellard 
206275be901cSPeter Crosthwaite #ifndef ELF_MACHINE
206375be901cSPeter Crosthwaite #define ELF_MACHINE ELF_ARCH
206475be901cSPeter Crosthwaite #endif
206575be901cSPeter Crosthwaite 
2066d276a604SPeter Crosthwaite #ifndef elf_check_arch
2067d276a604SPeter Crosthwaite #define elf_check_arch(x) ((x) == ELF_ARCH)
2068d276a604SPeter Crosthwaite #endif
2069d276a604SPeter Crosthwaite 
2070ace3d654SCarlo Marcelo Arenas Belón #ifndef elf_check_abi
2071ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (1)
2072ace3d654SCarlo Marcelo Arenas Belón #endif
2073ace3d654SCarlo Marcelo Arenas Belón 
207415338fd7Sbellard #ifndef ELF_HWCAP
207515338fd7Sbellard #define ELF_HWCAP 0
207615338fd7Sbellard #endif
207715338fd7Sbellard 
20787c4ee5bcSRichard Henderson #ifndef STACK_GROWS_DOWN
20797c4ee5bcSRichard Henderson #define STACK_GROWS_DOWN 1
20807c4ee5bcSRichard Henderson #endif
20817c4ee5bcSRichard Henderson 
20827c4ee5bcSRichard Henderson #ifndef STACK_ALIGNMENT
20837c4ee5bcSRichard Henderson #define STACK_ALIGNMENT 16
20847c4ee5bcSRichard Henderson #endif
20857c4ee5bcSRichard Henderson 
2086992f48a0Sblueswir1 #ifdef TARGET_ABI32
2087cb33da57Sblueswir1 #undef ELF_CLASS
2088992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
2089cb33da57Sblueswir1 #undef bswaptls
2090cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
2091cb33da57Sblueswir1 #endif
2092cb33da57Sblueswir1 
2093872f3d04SRichard Henderson #ifndef EXSTACK_DEFAULT
2094872f3d04SRichard Henderson #define EXSTACK_DEFAULT false
2095872f3d04SRichard Henderson #endif
2096872f3d04SRichard Henderson 
209731e31b8aSbellard #include "elf.h"
209809bfb054Sbellard 
2099e8384b37SRichard Henderson /* We must delay the following stanzas until after "elf.h". */
2100e8384b37SRichard Henderson #if defined(TARGET_AARCH64)
2101e8384b37SRichard Henderson 
2102e8384b37SRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
2103e8384b37SRichard Henderson                                     const uint32_t *data,
2104e8384b37SRichard Henderson                                     struct image_info *info,
2105e8384b37SRichard Henderson                                     Error **errp)
2106e8384b37SRichard Henderson {
2107e8384b37SRichard Henderson     if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
2108e8384b37SRichard Henderson         if (pr_datasz != sizeof(uint32_t)) {
2109e8384b37SRichard Henderson             error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
2110e8384b37SRichard Henderson             return false;
2111e8384b37SRichard Henderson         }
2112e8384b37SRichard Henderson         /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
2113e8384b37SRichard Henderson         info->note_flags = *data;
2114e8384b37SRichard Henderson     }
2115e8384b37SRichard Henderson     return true;
2116e8384b37SRichard Henderson }
2117e8384b37SRichard Henderson #define ARCH_USE_GNU_PROPERTY 1
2118e8384b37SRichard Henderson 
2119e8384b37SRichard Henderson #else
2120e8384b37SRichard Henderson 
212183f990ebSRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
212283f990ebSRichard Henderson                                     const uint32_t *data,
212383f990ebSRichard Henderson                                     struct image_info *info,
212483f990ebSRichard Henderson                                     Error **errp)
212583f990ebSRichard Henderson {
212683f990ebSRichard Henderson     g_assert_not_reached();
212783f990ebSRichard Henderson }
212883f990ebSRichard Henderson #define ARCH_USE_GNU_PROPERTY 0
212983f990ebSRichard Henderson 
2130e8384b37SRichard Henderson #endif
2131e8384b37SRichard Henderson 
213209bfb054Sbellard struct exec
213309bfb054Sbellard {
213409bfb054Sbellard     unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
213509bfb054Sbellard     unsigned int a_text;   /* length of text, in bytes */
213609bfb054Sbellard     unsigned int a_data;   /* length of data, in bytes */
213709bfb054Sbellard     unsigned int a_bss;    /* length of uninitialized data area, in bytes */
213809bfb054Sbellard     unsigned int a_syms;   /* length of symbol table data in file, in bytes */
213909bfb054Sbellard     unsigned int a_entry;  /* start address */
214009bfb054Sbellard     unsigned int a_trsize; /* length of relocation info for text, in bytes */
214109bfb054Sbellard     unsigned int a_drsize; /* length of relocation info for data, in bytes */
214209bfb054Sbellard };
214309bfb054Sbellard 
214409bfb054Sbellard 
214509bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
214609bfb054Sbellard #define OMAGIC 0407
214709bfb054Sbellard #define NMAGIC 0410
214809bfb054Sbellard #define ZMAGIC 0413
214909bfb054Sbellard #define QMAGIC 0314
215009bfb054Sbellard 
2151e0d1673dSLirong Yuan #define DLINFO_ITEMS 16
215231e31b8aSbellard 
215309bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
215409bfb054Sbellard {
215509bfb054Sbellard     memcpy(to, from, n);
215609bfb054Sbellard }
215709bfb054Sbellard 
215831e31b8aSbellard #ifdef BSWAP_NEEDED
215992a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
216031e31b8aSbellard {
216131e31b8aSbellard     bswap16s(&ehdr->e_type);            /* Object file type */
216231e31b8aSbellard     bswap16s(&ehdr->e_machine);         /* Architecture */
216331e31b8aSbellard     bswap32s(&ehdr->e_version);         /* Object file version */
216492a31b1fSbellard     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
216592a31b1fSbellard     bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
216692a31b1fSbellard     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
216731e31b8aSbellard     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
216831e31b8aSbellard     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
216931e31b8aSbellard     bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
217031e31b8aSbellard     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
217131e31b8aSbellard     bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
217231e31b8aSbellard     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
217331e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
217431e31b8aSbellard }
217531e31b8aSbellard 
2176991f8f0cSRichard Henderson static void bswap_phdr(struct elf_phdr *phdr, int phnum)
217731e31b8aSbellard {
2178991f8f0cSRichard Henderson     int i;
2179991f8f0cSRichard Henderson     for (i = 0; i < phnum; ++i, ++phdr) {
218031e31b8aSbellard         bswap32s(&phdr->p_type);        /* Segment type */
2181991f8f0cSRichard Henderson         bswap32s(&phdr->p_flags);       /* Segment flags */
218292a31b1fSbellard         bswaptls(&phdr->p_offset);      /* Segment file offset */
218392a31b1fSbellard         bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
218492a31b1fSbellard         bswaptls(&phdr->p_paddr);       /* Segment physical address */
218592a31b1fSbellard         bswaptls(&phdr->p_filesz);      /* Segment size in file */
218692a31b1fSbellard         bswaptls(&phdr->p_memsz);       /* Segment size in memory */
218792a31b1fSbellard         bswaptls(&phdr->p_align);       /* Segment alignment */
218831e31b8aSbellard     }
2189991f8f0cSRichard Henderson }
2190689f936fSbellard 
2191991f8f0cSRichard Henderson static void bswap_shdr(struct elf_shdr *shdr, int shnum)
2192689f936fSbellard {
2193991f8f0cSRichard Henderson     int i;
2194991f8f0cSRichard Henderson     for (i = 0; i < shnum; ++i, ++shdr) {
2195689f936fSbellard         bswap32s(&shdr->sh_name);
2196689f936fSbellard         bswap32s(&shdr->sh_type);
219792a31b1fSbellard         bswaptls(&shdr->sh_flags);
219892a31b1fSbellard         bswaptls(&shdr->sh_addr);
219992a31b1fSbellard         bswaptls(&shdr->sh_offset);
220092a31b1fSbellard         bswaptls(&shdr->sh_size);
2201689f936fSbellard         bswap32s(&shdr->sh_link);
2202689f936fSbellard         bswap32s(&shdr->sh_info);
220392a31b1fSbellard         bswaptls(&shdr->sh_addralign);
220492a31b1fSbellard         bswaptls(&shdr->sh_entsize);
2205689f936fSbellard     }
2206991f8f0cSRichard Henderson }
2207689f936fSbellard 
22087a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
2209689f936fSbellard {
2210689f936fSbellard     bswap32s(&sym->st_name);
22117a3148a9Sj_mayer     bswaptls(&sym->st_value);
22127a3148a9Sj_mayer     bswaptls(&sym->st_size);
2213689f936fSbellard     bswap16s(&sym->st_shndx);
2214689f936fSbellard }
22155dd0db52SStefan Markovic 
22165dd0db52SStefan Markovic #ifdef TARGET_MIPS
22175dd0db52SStefan Markovic static void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags)
22185dd0db52SStefan Markovic {
22195dd0db52SStefan Markovic     bswap16s(&abiflags->version);
22205dd0db52SStefan Markovic     bswap32s(&abiflags->ases);
22215dd0db52SStefan Markovic     bswap32s(&abiflags->isa_ext);
22225dd0db52SStefan Markovic     bswap32s(&abiflags->flags1);
22235dd0db52SStefan Markovic     bswap32s(&abiflags->flags2);
22245dd0db52SStefan Markovic }
22255dd0db52SStefan Markovic #endif
2226991f8f0cSRichard Henderson #else
2227991f8f0cSRichard Henderson static inline void bswap_ehdr(struct elfhdr *ehdr) { }
2228991f8f0cSRichard Henderson static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
2229991f8f0cSRichard Henderson static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
2230991f8f0cSRichard Henderson static inline void bswap_sym(struct elf_sym *sym) { }
22315dd0db52SStefan Markovic #ifdef TARGET_MIPS
22325dd0db52SStefan Markovic static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { }
22335dd0db52SStefan Markovic #endif
223431e31b8aSbellard #endif
223531e31b8aSbellard 
2236edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
22379349b4f9SAndreas Färber static int elf_core_dump(int, const CPUArchState *);
2238edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
223986cf82dcSRichard Henderson static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
224086cf82dcSRichard Henderson                          abi_ulong load_bias);
2241edf8e2afSMika Westerberg 
22429058abddSRichard Henderson /* Verify the portions of EHDR within E_IDENT for the target.
22439058abddSRichard Henderson    This can be performed before bswapping the entire header.  */
22449058abddSRichard Henderson static bool elf_check_ident(struct elfhdr *ehdr)
22459058abddSRichard Henderson {
22469058abddSRichard Henderson     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
22479058abddSRichard Henderson             && ehdr->e_ident[EI_MAG1] == ELFMAG1
22489058abddSRichard Henderson             && ehdr->e_ident[EI_MAG2] == ELFMAG2
22499058abddSRichard Henderson             && ehdr->e_ident[EI_MAG3] == ELFMAG3
22509058abddSRichard Henderson             && ehdr->e_ident[EI_CLASS] == ELF_CLASS
22519058abddSRichard Henderson             && ehdr->e_ident[EI_DATA] == ELF_DATA
22529058abddSRichard Henderson             && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
22539058abddSRichard Henderson }
22549058abddSRichard Henderson 
22559058abddSRichard Henderson /* Verify the portions of EHDR outside of E_IDENT for the target.
22569058abddSRichard Henderson    This has to wait until after bswapping the header.  */
22579058abddSRichard Henderson static bool elf_check_ehdr(struct elfhdr *ehdr)
22589058abddSRichard Henderson {
22599058abddSRichard Henderson     return (elf_check_arch(ehdr->e_machine)
2260ace3d654SCarlo Marcelo Arenas Belón             && elf_check_abi(ehdr->e_flags)
22619058abddSRichard Henderson             && ehdr->e_ehsize == sizeof(struct elfhdr)
22629058abddSRichard Henderson             && ehdr->e_phentsize == sizeof(struct elf_phdr)
22639058abddSRichard Henderson             && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
22649058abddSRichard Henderson }
22659058abddSRichard Henderson 
226631e31b8aSbellard /*
2267e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
226831e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
226931e31b8aSbellard  * to be put directly into the top of new user memory.
227031e31b8aSbellard  *
227131e31b8aSbellard  */
227259baae9aSStefan Brüns static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch,
227359baae9aSStefan Brüns                                   abi_ulong p, abi_ulong stack_limit)
227431e31b8aSbellard {
227559baae9aSStefan Brüns     char *tmp;
22767c4ee5bcSRichard Henderson     int len, i;
227759baae9aSStefan Brüns     abi_ulong top = p;
227831e31b8aSbellard 
227931e31b8aSbellard     if (!p) {
228031e31b8aSbellard         return 0;       /* bullet-proofing */
228131e31b8aSbellard     }
228259baae9aSStefan Brüns 
22837c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
22847c4ee5bcSRichard Henderson         int offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
22857c4ee5bcSRichard Henderson         for (i = argc - 1; i >= 0; --i) {
22867c4ee5bcSRichard Henderson             tmp = argv[i];
2287edf779ffSbellard             if (!tmp) {
228831e31b8aSbellard                 fprintf(stderr, "VFS: argc is wrong");
228931e31b8aSbellard                 exit(-1);
229031e31b8aSbellard             }
229159baae9aSStefan Brüns             len = strlen(tmp) + 1;
229259baae9aSStefan Brüns             tmp += len;
229359baae9aSStefan Brüns 
229459baae9aSStefan Brüns             if (len > (p - stack_limit)) {
229531e31b8aSbellard                 return 0;
229631e31b8aSbellard             }
229731e31b8aSbellard             while (len) {
229831e31b8aSbellard                 int bytes_to_copy = (len > offset) ? offset : len;
229931e31b8aSbellard                 tmp -= bytes_to_copy;
230031e31b8aSbellard                 p -= bytes_to_copy;
230131e31b8aSbellard                 offset -= bytes_to_copy;
230231e31b8aSbellard                 len -= bytes_to_copy;
230359baae9aSStefan Brüns 
230459baae9aSStefan Brüns                 memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
230559baae9aSStefan Brüns 
230659baae9aSStefan Brüns                 if (offset == 0) {
230759baae9aSStefan Brüns                     memcpy_to_target(p, scratch, top - p);
230859baae9aSStefan Brüns                     top = p;
230959baae9aSStefan Brüns                     offset = TARGET_PAGE_SIZE;
231031e31b8aSbellard                 }
231131e31b8aSbellard             }
231231e31b8aSbellard         }
23137c4ee5bcSRichard Henderson         if (p != top) {
231459baae9aSStefan Brüns             memcpy_to_target(p, scratch + offset, top - p);
231559baae9aSStefan Brüns         }
23167c4ee5bcSRichard Henderson     } else {
23177c4ee5bcSRichard Henderson         int remaining = TARGET_PAGE_SIZE - (p % TARGET_PAGE_SIZE);
23187c4ee5bcSRichard Henderson         for (i = 0; i < argc; ++i) {
23197c4ee5bcSRichard Henderson             tmp = argv[i];
23207c4ee5bcSRichard Henderson             if (!tmp) {
23217c4ee5bcSRichard Henderson                 fprintf(stderr, "VFS: argc is wrong");
23227c4ee5bcSRichard Henderson                 exit(-1);
23237c4ee5bcSRichard Henderson             }
23247c4ee5bcSRichard Henderson             len = strlen(tmp) + 1;
23257c4ee5bcSRichard Henderson             if (len > (stack_limit - p)) {
23267c4ee5bcSRichard Henderson                 return 0;
23277c4ee5bcSRichard Henderson             }
23287c4ee5bcSRichard Henderson             while (len) {
23297c4ee5bcSRichard Henderson                 int bytes_to_copy = (len > remaining) ? remaining : len;
23307c4ee5bcSRichard Henderson 
23317c4ee5bcSRichard Henderson                 memcpy_fromfs(scratch + (p - top), tmp, bytes_to_copy);
23327c4ee5bcSRichard Henderson 
23337c4ee5bcSRichard Henderson                 tmp += bytes_to_copy;
23347c4ee5bcSRichard Henderson                 remaining -= bytes_to_copy;
23357c4ee5bcSRichard Henderson                 p += bytes_to_copy;
23367c4ee5bcSRichard Henderson                 len -= bytes_to_copy;
23377c4ee5bcSRichard Henderson 
23387c4ee5bcSRichard Henderson                 if (remaining == 0) {
23397c4ee5bcSRichard Henderson                     memcpy_to_target(top, scratch, p - top);
23407c4ee5bcSRichard Henderson                     top = p;
23417c4ee5bcSRichard Henderson                     remaining = TARGET_PAGE_SIZE;
23427c4ee5bcSRichard Henderson                 }
23437c4ee5bcSRichard Henderson             }
23447c4ee5bcSRichard Henderson         }
23457c4ee5bcSRichard Henderson         if (p != top) {
23467c4ee5bcSRichard Henderson             memcpy_to_target(top, scratch, p - top);
23477c4ee5bcSRichard Henderson         }
23487c4ee5bcSRichard Henderson     }
234959baae9aSStefan Brüns 
235031e31b8aSbellard     return p;
235131e31b8aSbellard }
235231e31b8aSbellard 
235359baae9aSStefan Brüns /* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of
235459baae9aSStefan Brüns  * argument/environment space. Newer kernels (>2.6.33) allow more,
235559baae9aSStefan Brüns  * dependent on stack size, but guarantee at least 32 pages for
235659baae9aSStefan Brüns  * backwards compatibility.
235759baae9aSStefan Brüns  */
235859baae9aSStefan Brüns #define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE)
235959baae9aSStefan Brüns 
236059baae9aSStefan Brüns static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
236131e31b8aSbellard                                  struct image_info *info)
236231e31b8aSbellard {
236359baae9aSStefan Brüns     abi_ulong size, error, guard;
2364872f3d04SRichard Henderson     int prot;
236531e31b8aSbellard 
2366703e0e89SRichard Henderson     size = guest_stack_size;
236759baae9aSStefan Brüns     if (size < STACK_LOWER_LIMIT) {
236859baae9aSStefan Brüns         size = STACK_LOWER_LIMIT;
236960dcbcb5SRichard Henderson     }
2370f4388205SHelge Deller 
2371f4388205SHelge Deller     if (STACK_GROWS_DOWN) {
237260dcbcb5SRichard Henderson         guard = TARGET_PAGE_SIZE;
23738e3b0cbbSMarc-André Lureau         if (guard < qemu_real_host_page_size()) {
23748e3b0cbbSMarc-André Lureau             guard = qemu_real_host_page_size();
237560dcbcb5SRichard Henderson         }
2376f4388205SHelge Deller     } else {
2377f4388205SHelge Deller         /* no guard page for hppa target where stack grows upwards. */
2378f4388205SHelge Deller         guard = 0;
2379f4388205SHelge Deller     }
238060dcbcb5SRichard Henderson 
2381872f3d04SRichard Henderson     prot = PROT_READ | PROT_WRITE;
2382872f3d04SRichard Henderson     if (info->exec_stack) {
2383872f3d04SRichard Henderson         prot |= PROT_EXEC;
2384872f3d04SRichard Henderson     }
2385872f3d04SRichard Henderson     error = target_mmap(0, size + guard, prot,
238660dcbcb5SRichard Henderson                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
238709bfb054Sbellard     if (error == -1) {
238860dcbcb5SRichard Henderson         perror("mmap stack");
238931e31b8aSbellard         exit(-1);
239031e31b8aSbellard     }
239131e31b8aSbellard 
239260dcbcb5SRichard Henderson     /* We reserve one extra page at the top of the stack as guard.  */
23937c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
239460dcbcb5SRichard Henderson         target_mprotect(error, guard, PROT_NONE);
239560dcbcb5SRichard Henderson         info->stack_limit = error + guard;
239659baae9aSStefan Brüns         return info->stack_limit + size - sizeof(void *);
23977c4ee5bcSRichard Henderson     } else {
23987c4ee5bcSRichard Henderson         info->stack_limit = error + size;
23997c4ee5bcSRichard Henderson         return error;
24007c4ee5bcSRichard Henderson     }
240131e31b8aSbellard }
240231e31b8aSbellard 
24032d385be6SRichard Henderson /**
24042d385be6SRichard Henderson  * zero_bss:
24052d385be6SRichard Henderson  *
24062d385be6SRichard Henderson  * Map and zero the bss.  We need to explicitly zero any fractional pages
24072d385be6SRichard Henderson  * after the data section (i.e. bss).  Return false on mapping failure.
24082d385be6SRichard Henderson  */
2409e6e66b03SRichard Henderson static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss,
2410e6e66b03SRichard Henderson                      int prot, Error **errp)
241131e31b8aSbellard {
24122d385be6SRichard Henderson     abi_ulong align_bss;
2413cf129f3aSRichard Henderson 
2414e6e66b03SRichard Henderson     /* We only expect writable bss; the code segment shouldn't need this. */
2415e6e66b03SRichard Henderson     if (!(prot & PROT_WRITE)) {
2416e6e66b03SRichard Henderson         error_setg(errp, "PT_LOAD with non-writable bss");
2417e6e66b03SRichard Henderson         return false;
2418e6e66b03SRichard Henderson     }
2419e6e66b03SRichard Henderson 
24202d385be6SRichard Henderson     align_bss = TARGET_PAGE_ALIGN(start_bss);
24212d385be6SRichard Henderson     end_bss = TARGET_PAGE_ALIGN(end_bss);
2422cf129f3aSRichard Henderson 
24232d385be6SRichard Henderson     if (start_bss < align_bss) {
24242d385be6SRichard Henderson         int flags = page_get_flags(start_bss);
2425cf129f3aSRichard Henderson 
2426e6e66b03SRichard Henderson         if (!(flags & PAGE_BITS)) {
2427e6e66b03SRichard Henderson             /*
2428e6e66b03SRichard Henderson              * The whole address space of the executable was reserved
2429e6e66b03SRichard Henderson              * at the start, therefore all pages will be VALID.
2430e6e66b03SRichard Henderson              * But assuming there are no PROT_NONE PT_LOAD segments,
2431e6e66b03SRichard Henderson              * a PROT_NONE page means no data all bss, and we can
2432e6e66b03SRichard Henderson              * simply extend the new anon mapping back to the start
2433e6e66b03SRichard Henderson              * of the page of bss.
2434e6e66b03SRichard Henderson              */
24352d385be6SRichard Henderson             align_bss -= TARGET_PAGE_SIZE;
24362d385be6SRichard Henderson         } else {
2437e6e66b03SRichard Henderson             /*
2438e6e66b03SRichard Henderson              * The start of the bss shares a page with something.
2439e6e66b03SRichard Henderson              * The only thing that we expect is the data section,
2440e6e66b03SRichard Henderson              * which would already be marked writable.
2441e6e66b03SRichard Henderson              * Overlapping the RX code segment seems malformed.
2442e6e66b03SRichard Henderson              */
2443e6e66b03SRichard Henderson             if (!(flags & PAGE_WRITE)) {
2444e6e66b03SRichard Henderson                 error_setg(errp, "PT_LOAD with bss overlapping "
2445e6e66b03SRichard Henderson                            "non-writable page");
2446e6e66b03SRichard Henderson                 return false;
2447e6e66b03SRichard Henderson             }
2448e6e66b03SRichard Henderson 
2449e6e66b03SRichard Henderson             /* The page is already mapped and writable. */
2450e6e66b03SRichard Henderson             memset(g2h_untagged(start_bss), 0, align_bss - start_bss);
245131e31b8aSbellard         }
2452f46e9a0bSTom Musta     }
2453cf129f3aSRichard Henderson 
2454e6e66b03SRichard Henderson     if (align_bss < end_bss &&
24552d385be6SRichard Henderson         target_mmap(align_bss, end_bss - align_bss, prot,
2456e6e66b03SRichard Henderson                     MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) {
2457e6e66b03SRichard Henderson         error_setg_errno(errp, errno, "Error mapping bss");
2458e6e66b03SRichard Henderson         return false;
2459e6e66b03SRichard Henderson     }
2460e6e66b03SRichard Henderson     return true;
2461853d6f7aSbellard }
2462853d6f7aSbellard 
2463d2796be6SMax Filippov #if defined(TARGET_ARM)
2464cf58affeSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2465cf58affeSChristophe Lyon {
2466cf58affeSChristophe Lyon     return exec->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC;
2467cf58affeSChristophe Lyon }
2468d2796be6SMax Filippov #elif defined(TARGET_XTENSA)
2469d2796be6SMax Filippov static int elf_is_fdpic(struct elfhdr *exec)
2470d2796be6SMax Filippov {
2471d2796be6SMax Filippov     return exec->e_ident[EI_OSABI] == ELFOSABI_XTENSA_FDPIC;
2472d2796be6SMax Filippov }
2473cf58affeSChristophe Lyon #else
2474a99856cdSChristophe Lyon /* Default implementation, always false.  */
2475a99856cdSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2476a99856cdSChristophe Lyon {
2477a99856cdSChristophe Lyon     return 0;
2478a99856cdSChristophe Lyon }
2479cf58affeSChristophe Lyon #endif
2480a99856cdSChristophe Lyon 
24811af02e83SMike Frysinger static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
24821af02e83SMike Frysinger {
24831af02e83SMike Frysinger     uint16_t n;
24841af02e83SMike Frysinger     struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
24851af02e83SMike Frysinger 
24861af02e83SMike Frysinger     /* elf32_fdpic_loadseg */
24871af02e83SMike Frysinger     n = info->nsegs;
24881af02e83SMike Frysinger     while (n--) {
24891af02e83SMike Frysinger         sp -= 12;
24901af02e83SMike Frysinger         put_user_u32(loadsegs[n].addr, sp+0);
24911af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_vaddr, sp+4);
24921af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_memsz, sp+8);
24931af02e83SMike Frysinger     }
24941af02e83SMike Frysinger 
24951af02e83SMike Frysinger     /* elf32_fdpic_loadmap */
24961af02e83SMike Frysinger     sp -= 4;
24971af02e83SMike Frysinger     put_user_u16(0, sp+0); /* version */
24981af02e83SMike Frysinger     put_user_u16(info->nsegs, sp+2); /* nsegs */
24991af02e83SMike Frysinger 
25001af02e83SMike Frysinger     info->personality = PER_LINUX_FDPIC;
25011af02e83SMike Frysinger     info->loadmap_addr = sp;
25021af02e83SMike Frysinger 
25031af02e83SMike Frysinger     return sp;
25041af02e83SMike Frysinger }
25051af02e83SMike Frysinger 
2506992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
250731e31b8aSbellard                                    struct elfhdr *exec,
25088e62a717SRichard Henderson                                    struct image_info *info,
2509c40f621aSRichard Henderson                                    struct image_info *interp_info,
2510c40f621aSRichard Henderson                                    struct image_info *vdso_info)
251131e31b8aSbellard {
2512992f48a0Sblueswir1     abi_ulong sp;
25137c4ee5bcSRichard Henderson     abi_ulong u_argc, u_argv, u_envp, u_auxv;
251453a5960aSpbrook     int size;
251514322badSLaurent ALFONSI     int i;
251614322badSLaurent ALFONSI     abi_ulong u_rand_bytes;
251714322badSLaurent ALFONSI     uint8_t k_rand_bytes[16];
2518fcdc0ab4SJiaxun Yang     abi_ulong u_platform, u_base_platform;
2519fcdc0ab4SJiaxun Yang     const char *k_platform, *k_base_platform;
2520863cf0b7Sj_mayer     const int n = sizeof(elf_addr_t);
252131e31b8aSbellard 
252253a5960aSpbrook     sp = p;
25231af02e83SMike Frysinger 
25241af02e83SMike Frysinger     /* Needs to be before we load the env/argc/... */
25251af02e83SMike Frysinger     if (elf_is_fdpic(exec)) {
25261af02e83SMike Frysinger         /* Need 4 byte alignment for these structs */
25271af02e83SMike Frysinger         sp &= ~3;
25281af02e83SMike Frysinger         sp = loader_build_fdpic_loadmap(info, sp);
25291af02e83SMike Frysinger         info->other_info = interp_info;
25301af02e83SMike Frysinger         if (interp_info) {
25311af02e83SMike Frysinger             interp_info->other_info = info;
25321af02e83SMike Frysinger             sp = loader_build_fdpic_loadmap(interp_info, sp);
25333cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = interp_info->loadmap_addr;
25343cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = interp_info->pt_dynamic_addr;
25353cb10cfaSChristophe Lyon         } else {
25363cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = 0;
25373cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = 0;
25381af02e83SMike Frysinger         }
25391af02e83SMike Frysinger     }
25401af02e83SMike Frysinger 
2541fcdc0ab4SJiaxun Yang     u_base_platform = 0;
2542fcdc0ab4SJiaxun Yang     k_base_platform = ELF_BASE_PLATFORM;
2543fcdc0ab4SJiaxun Yang     if (k_base_platform) {
2544fcdc0ab4SJiaxun Yang         size_t len = strlen(k_base_platform) + 1;
2545fcdc0ab4SJiaxun Yang         if (STACK_GROWS_DOWN) {
2546fcdc0ab4SJiaxun Yang             sp -= (len + n - 1) & ~(n - 1);
2547fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2548fcdc0ab4SJiaxun Yang             /* FIXME - check return value of memcpy_to_target() for failure */
2549fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2550fcdc0ab4SJiaxun Yang         } else {
2551fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2552fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2553fcdc0ab4SJiaxun Yang             sp += len + 1;
2554fcdc0ab4SJiaxun Yang         }
2555fcdc0ab4SJiaxun Yang     }
2556fcdc0ab4SJiaxun Yang 
255753a5960aSpbrook     u_platform = 0;
255815338fd7Sbellard     k_platform = ELF_PLATFORM;
255915338fd7Sbellard     if (k_platform) {
256015338fd7Sbellard         size_t len = strlen(k_platform) + 1;
25617c4ee5bcSRichard Henderson         if (STACK_GROWS_DOWN) {
256253a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
256353a5960aSpbrook             u_platform = sp;
2564579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
256553a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
25667c4ee5bcSRichard Henderson         } else {
25677c4ee5bcSRichard Henderson             memcpy_to_target(sp, k_platform, len);
25687c4ee5bcSRichard Henderson             u_platform = sp;
25697c4ee5bcSRichard Henderson             sp += len + 1;
25707c4ee5bcSRichard Henderson         }
25717c4ee5bcSRichard Henderson     }
25727c4ee5bcSRichard Henderson 
25737c4ee5bcSRichard Henderson     /* Provide 16 byte alignment for the PRNG, and basic alignment for
25747c4ee5bcSRichard Henderson      * the argv and envp pointers.
25757c4ee5bcSRichard Henderson      */
25767c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
25777c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_DOWN(sp, 16);
25787c4ee5bcSRichard Henderson     } else {
25797c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp, 16);
258015338fd7Sbellard     }
258114322badSLaurent ALFONSI 
258214322badSLaurent ALFONSI     /*
2583c6a2377fSRichard Henderson      * Generate 16 random bytes for userspace PRNG seeding.
258414322badSLaurent ALFONSI      */
2585c6a2377fSRichard Henderson     qemu_guest_getrandom_nofail(k_rand_bytes, sizeof(k_rand_bytes));
25867c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
258714322badSLaurent ALFONSI         sp -= 16;
258814322badSLaurent ALFONSI         u_rand_bytes = sp;
258914322badSLaurent ALFONSI         /* FIXME - check return value of memcpy_to_target() for failure */
259014322badSLaurent ALFONSI         memcpy_to_target(sp, k_rand_bytes, 16);
25917c4ee5bcSRichard Henderson     } else {
25927c4ee5bcSRichard Henderson         memcpy_to_target(sp, k_rand_bytes, 16);
25937c4ee5bcSRichard Henderson         u_rand_bytes = sp;
25947c4ee5bcSRichard Henderson         sp += 16;
25957c4ee5bcSRichard Henderson     }
259614322badSLaurent ALFONSI 
259753a5960aSpbrook     size = (DLINFO_ITEMS + 1) * 2;
2598c40f621aSRichard Henderson     if (k_base_platform) {
2599fcdc0ab4SJiaxun Yang         size += 2;
2600c40f621aSRichard Henderson     }
2601c40f621aSRichard Henderson     if (k_platform) {
260253a5960aSpbrook         size += 2;
2603c40f621aSRichard Henderson     }
2604c40f621aSRichard Henderson     if (vdso_info) {
2605c40f621aSRichard Henderson         size += 2;
2606c40f621aSRichard Henderson     }
2607f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
260853a5960aSpbrook     size += DLINFO_ARCH_ITEMS * 2;
2609f5155289Sbellard #endif
2610ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2611ad6919dcSPeter Maydell     size += 2;
2612ad6919dcSPeter Maydell #endif
2613f516511eSPeter Maydell     info->auxv_len = size * n;
2614f516511eSPeter Maydell 
261553a5960aSpbrook     size += envc + argc + 2;
2616b9329d4bSRichard Henderson     size += 1;  /* argc itself */
261753a5960aSpbrook     size *= n;
26187c4ee5bcSRichard Henderson 
26197c4ee5bcSRichard Henderson     /* Allocate space and finalize stack alignment for entry now.  */
26207c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
26217c4ee5bcSRichard Henderson         u_argc = QEMU_ALIGN_DOWN(sp - size, STACK_ALIGNMENT);
26227c4ee5bcSRichard Henderson         sp = u_argc;
26237c4ee5bcSRichard Henderson     } else {
26247c4ee5bcSRichard Henderson         u_argc = sp;
26257c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp + size, STACK_ALIGNMENT);
26267c4ee5bcSRichard Henderson     }
26277c4ee5bcSRichard Henderson 
26287c4ee5bcSRichard Henderson     u_argv = u_argc + n;
26297c4ee5bcSRichard Henderson     u_envp = u_argv + (argc + 1) * n;
26307c4ee5bcSRichard Henderson     u_auxv = u_envp + (envc + 1) * n;
26317c4ee5bcSRichard Henderson     info->saved_auxv = u_auxv;
263260f1c801SRichard Henderson     info->argc = argc;
263360f1c801SRichard Henderson     info->envc = envc;
263460f1c801SRichard Henderson     info->argv = u_argv;
263560f1c801SRichard Henderson     info->envp = u_envp;
2636f5155289Sbellard 
2637863cf0b7Sj_mayer     /* This is correct because Linux defines
2638863cf0b7Sj_mayer      * elf_addr_t as Elf32_Off / Elf64_Off
2639863cf0b7Sj_mayer      */
264053a5960aSpbrook #define NEW_AUX_ENT(id, val) do {               \
26417c4ee5bcSRichard Henderson         put_user_ual(id, u_auxv);  u_auxv += n; \
26427c4ee5bcSRichard Henderson         put_user_ual(val, u_auxv); u_auxv += n; \
264353a5960aSpbrook     } while(0)
26442f619698Sbellard 
264582991bedSPeter Maydell #ifdef ARCH_DLINFO
264682991bedSPeter Maydell     /*
264782991bedSPeter Maydell      * ARCH_DLINFO must come first so platform specific code can enforce
264882991bedSPeter Maydell      * special alignment requirements on the AUXV if necessary (eg. PPC).
264982991bedSPeter Maydell      */
265082991bedSPeter Maydell     ARCH_DLINFO;
265182991bedSPeter Maydell #endif
2652f516511eSPeter Maydell     /* There must be exactly DLINFO_ITEMS entries here, or the assert
2653f516511eSPeter Maydell      * on info->auxv_len will trigger.
2654f516511eSPeter Maydell      */
26558e62a717SRichard Henderson     NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
2656992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
2657992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
265833143c44SLaurent Vivier     if ((info->alignment & ~qemu_host_page_mask) != 0) {
265933143c44SLaurent Vivier         /* Target doesn't support host page size alignment */
266033143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
266133143c44SLaurent Vivier     } else {
266233143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(MAX(TARGET_PAGE_SIZE,
266333143c44SLaurent Vivier                                                qemu_host_page_size)));
266433143c44SLaurent Vivier     }
26658e62a717SRichard Henderson     NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
2666992f48a0Sblueswir1     NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
26678e62a717SRichard Henderson     NEW_AUX_ENT(AT_ENTRY, info->entry);
2668992f48a0Sblueswir1     NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
2669992f48a0Sblueswir1     NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
2670992f48a0Sblueswir1     NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
2671992f48a0Sblueswir1     NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
2672992f48a0Sblueswir1     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
2673a07c67dfSpbrook     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
267414322badSLaurent ALFONSI     NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
2675444cd5c3SMarco A L Barbosa     NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
2676e0d1673dSLirong Yuan     NEW_AUX_ENT(AT_EXECFN, info->file_string);
267714322badSLaurent ALFONSI 
2678ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2679ad6919dcSPeter Maydell     NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
2680ad6919dcSPeter Maydell #endif
2681ad6919dcSPeter Maydell 
2682fcdc0ab4SJiaxun Yang     if (u_base_platform) {
2683fcdc0ab4SJiaxun Yang         NEW_AUX_ENT(AT_BASE_PLATFORM, u_base_platform);
2684fcdc0ab4SJiaxun Yang     }
26857c4ee5bcSRichard Henderson     if (u_platform) {
268653a5960aSpbrook         NEW_AUX_ENT(AT_PLATFORM, u_platform);
26877c4ee5bcSRichard Henderson     }
2688c40f621aSRichard Henderson     if (vdso_info) {
2689c40f621aSRichard Henderson         NEW_AUX_ENT(AT_SYSINFO_EHDR, vdso_info->load_addr);
2690c40f621aSRichard Henderson     }
26917c4ee5bcSRichard Henderson     NEW_AUX_ENT (AT_NULL, 0);
2692f5155289Sbellard #undef NEW_AUX_ENT
2693f5155289Sbellard 
2694f516511eSPeter Maydell     /* Check that our initial calculation of the auxv length matches how much
2695f516511eSPeter Maydell      * we actually put into it.
2696f516511eSPeter Maydell      */
2697f516511eSPeter Maydell     assert(info->auxv_len == u_auxv - info->saved_auxv);
2698edf8e2afSMika Westerberg 
26997c4ee5bcSRichard Henderson     put_user_ual(argc, u_argc);
27007c4ee5bcSRichard Henderson 
27017c4ee5bcSRichard Henderson     p = info->arg_strings;
27027c4ee5bcSRichard Henderson     for (i = 0; i < argc; ++i) {
27037c4ee5bcSRichard Henderson         put_user_ual(p, u_argv);
27047c4ee5bcSRichard Henderson         u_argv += n;
27057c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
27067c4ee5bcSRichard Henderson     }
27077c4ee5bcSRichard Henderson     put_user_ual(0, u_argv);
27087c4ee5bcSRichard Henderson 
27097c4ee5bcSRichard Henderson     p = info->env_strings;
27107c4ee5bcSRichard Henderson     for (i = 0; i < envc; ++i) {
27117c4ee5bcSRichard Henderson         put_user_ual(p, u_envp);
27127c4ee5bcSRichard Henderson         u_envp += n;
27137c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
27147c4ee5bcSRichard Henderson     }
27157c4ee5bcSRichard Henderson     put_user_ual(0, u_envp);
27167c4ee5bcSRichard Henderson 
271731e31b8aSbellard     return sp;
271831e31b8aSbellard }
271931e31b8aSbellard 
2720f5ef0e51SRichard Henderson #if defined(HI_COMMPAGE)
2721eee816c0SRichard Henderson #define LO_COMMPAGE -1
2722f5ef0e51SRichard Henderson #elif defined(LO_COMMPAGE)
272366346fafSRichard Henderson #define HI_COMMPAGE 0
2724f5ef0e51SRichard Henderson #else
2725f5ef0e51SRichard Henderson #define HI_COMMPAGE 0
2726eee816c0SRichard Henderson #define LO_COMMPAGE -1
2727d461b73eSRichard Henderson #ifndef INIT_GUEST_COMMPAGE
2728ee947430SAlex Bennée #define init_guest_commpage() true
2729ee947430SAlex Bennée #endif
2730d461b73eSRichard Henderson #endif
2731ee947430SAlex Bennée 
273206f38c66SRichard Henderson /**
273306f38c66SRichard Henderson  * pgb_try_mmap:
273406f38c66SRichard Henderson  * @addr: host start address
273506f38c66SRichard Henderson  * @addr_last: host last address
273606f38c66SRichard Henderson  * @keep: do not unmap the probe region
273706f38c66SRichard Henderson  *
273806f38c66SRichard Henderson  * Return 1 if [@addr, @addr_last] is not mapped in the host,
273906f38c66SRichard Henderson  * return 0 if it is not available to map, and -1 on mmap error.
274006f38c66SRichard Henderson  * If @keep, the region is left mapped on success, otherwise unmapped.
274106f38c66SRichard Henderson  */
274206f38c66SRichard Henderson static int pgb_try_mmap(uintptr_t addr, uintptr_t addr_last, bool keep)
274306f38c66SRichard Henderson {
274406f38c66SRichard Henderson     size_t size = addr_last - addr + 1;
274506f38c66SRichard Henderson     void *p = mmap((void *)addr, size, PROT_NONE,
274606f38c66SRichard Henderson                    MAP_ANONYMOUS | MAP_PRIVATE |
274706f38c66SRichard Henderson                    MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
274806f38c66SRichard Henderson     int ret;
274906f38c66SRichard Henderson 
275006f38c66SRichard Henderson     if (p == MAP_FAILED) {
275106f38c66SRichard Henderson         return errno == EEXIST ? 0 : -1;
275206f38c66SRichard Henderson     }
275306f38c66SRichard Henderson     ret = p == (void *)addr;
275406f38c66SRichard Henderson     if (!keep || !ret) {
275506f38c66SRichard Henderson         munmap(p, size);
275606f38c66SRichard Henderson     }
275706f38c66SRichard Henderson     return ret;
275806f38c66SRichard Henderson }
275906f38c66SRichard Henderson 
276006f38c66SRichard Henderson /**
276106f38c66SRichard Henderson  * pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t size, uintptr_t brk)
276206f38c66SRichard Henderson  * @addr: host address
276306f38c66SRichard Henderson  * @addr_last: host last address
276406f38c66SRichard Henderson  * @brk: host brk
276506f38c66SRichard Henderson  *
276606f38c66SRichard Henderson  * Like pgb_try_mmap, but additionally reserve some memory following brk.
276706f38c66SRichard Henderson  */
276806f38c66SRichard Henderson static int pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t addr_last,
276906f38c66SRichard Henderson                                  uintptr_t brk, bool keep)
277006f38c66SRichard Henderson {
277106f38c66SRichard Henderson     uintptr_t brk_last = brk + 16 * MiB - 1;
277206f38c66SRichard Henderson 
277306f38c66SRichard Henderson     /* Do not map anything close to the host brk. */
277406f38c66SRichard Henderson     if (addr <= brk_last && brk <= addr_last) {
277506f38c66SRichard Henderson         return 0;
277606f38c66SRichard Henderson     }
277706f38c66SRichard Henderson     return pgb_try_mmap(addr, addr_last, keep);
277806f38c66SRichard Henderson }
277906f38c66SRichard Henderson 
278006f38c66SRichard Henderson /**
278106f38c66SRichard Henderson  * pgb_try_mmap_set:
278206f38c66SRichard Henderson  * @ga: set of guest addrs
278306f38c66SRichard Henderson  * @base: guest_base
278406f38c66SRichard Henderson  * @brk: host brk
278506f38c66SRichard Henderson  *
278606f38c66SRichard Henderson  * Return true if all @ga can be mapped by the host at @base.
278706f38c66SRichard Henderson  * On success, retain the mapping at index 0 for reserved_va.
278806f38c66SRichard Henderson  */
278906f38c66SRichard Henderson 
279006f38c66SRichard Henderson typedef struct PGBAddrs {
279106f38c66SRichard Henderson     uintptr_t bounds[3][2]; /* start/last pairs */
279206f38c66SRichard Henderson     int nbounds;
279306f38c66SRichard Henderson } PGBAddrs;
279406f38c66SRichard Henderson 
279506f38c66SRichard Henderson static bool pgb_try_mmap_set(const PGBAddrs *ga, uintptr_t base, uintptr_t brk)
279606f38c66SRichard Henderson {
279706f38c66SRichard Henderson     for (int i = ga->nbounds - 1; i >= 0; --i) {
279806f38c66SRichard Henderson         if (pgb_try_mmap_skip_brk(ga->bounds[i][0] + base,
279906f38c66SRichard Henderson                                   ga->bounds[i][1] + base,
280006f38c66SRichard Henderson                                   brk, i == 0 && reserved_va) <= 0) {
280106f38c66SRichard Henderson             return false;
280206f38c66SRichard Henderson         }
280306f38c66SRichard Henderson     }
280406f38c66SRichard Henderson     return true;
280506f38c66SRichard Henderson }
280606f38c66SRichard Henderson 
280706f38c66SRichard Henderson /**
280806f38c66SRichard Henderson  * pgb_addr_set:
280906f38c66SRichard Henderson  * @ga: output set of guest addrs
281006f38c66SRichard Henderson  * @guest_loaddr: guest image low address
281106f38c66SRichard Henderson  * @guest_loaddr: guest image high address
281206f38c66SRichard Henderson  * @identity: create for identity mapping
281306f38c66SRichard Henderson  *
281406f38c66SRichard Henderson  * Fill in @ga with the image, COMMPAGE and NULL page.
281506f38c66SRichard Henderson  */
281606f38c66SRichard Henderson static bool pgb_addr_set(PGBAddrs *ga, abi_ulong guest_loaddr,
281706f38c66SRichard Henderson                          abi_ulong guest_hiaddr, bool try_identity)
281806f38c66SRichard Henderson {
281906f38c66SRichard Henderson     int n;
282006f38c66SRichard Henderson 
282106f38c66SRichard Henderson     /*
282206f38c66SRichard Henderson      * With a low commpage, or a guest mapped very low,
282306f38c66SRichard Henderson      * we may not be able to use the identity map.
282406f38c66SRichard Henderson      */
282506f38c66SRichard Henderson     if (try_identity) {
282606f38c66SRichard Henderson         if (LO_COMMPAGE != -1 && LO_COMMPAGE < mmap_min_addr) {
282706f38c66SRichard Henderson             return false;
282806f38c66SRichard Henderson         }
282906f38c66SRichard Henderson         if (guest_loaddr != 0 && guest_loaddr < mmap_min_addr) {
283006f38c66SRichard Henderson             return false;
283106f38c66SRichard Henderson         }
283206f38c66SRichard Henderson     }
283306f38c66SRichard Henderson 
283406f38c66SRichard Henderson     memset(ga, 0, sizeof(*ga));
283506f38c66SRichard Henderson     n = 0;
283606f38c66SRichard Henderson 
283706f38c66SRichard Henderson     if (reserved_va) {
283806f38c66SRichard Henderson         ga->bounds[n][0] = try_identity ? mmap_min_addr : 0;
283906f38c66SRichard Henderson         ga->bounds[n][1] = reserved_va;
284006f38c66SRichard Henderson         n++;
284106f38c66SRichard Henderson         /* LO_COMMPAGE and NULL handled by reserving from 0. */
284206f38c66SRichard Henderson     } else {
284306f38c66SRichard Henderson         /* Add any LO_COMMPAGE or NULL page. */
284406f38c66SRichard Henderson         if (LO_COMMPAGE != -1) {
284506f38c66SRichard Henderson             ga->bounds[n][0] = 0;
284606f38c66SRichard Henderson             ga->bounds[n][1] = LO_COMMPAGE + TARGET_PAGE_SIZE - 1;
284706f38c66SRichard Henderson             n++;
284806f38c66SRichard Henderson         } else if (!try_identity) {
284906f38c66SRichard Henderson             ga->bounds[n][0] = 0;
285006f38c66SRichard Henderson             ga->bounds[n][1] = TARGET_PAGE_SIZE - 1;
285106f38c66SRichard Henderson             n++;
285206f38c66SRichard Henderson         }
285306f38c66SRichard Henderson 
285406f38c66SRichard Henderson         /* Add the guest image for ET_EXEC. */
285506f38c66SRichard Henderson         if (guest_loaddr) {
285606f38c66SRichard Henderson             ga->bounds[n][0] = guest_loaddr;
285706f38c66SRichard Henderson             ga->bounds[n][1] = guest_hiaddr;
285806f38c66SRichard Henderson             n++;
285906f38c66SRichard Henderson         }
286006f38c66SRichard Henderson     }
286106f38c66SRichard Henderson 
286206f38c66SRichard Henderson     /*
286306f38c66SRichard Henderson      * Temporarily disable
286406f38c66SRichard Henderson      *   "comparison is always false due to limited range of data type"
286506f38c66SRichard Henderson      * due to comparison between unsigned and (possible) 0.
286606f38c66SRichard Henderson      */
286706f38c66SRichard Henderson #pragma GCC diagnostic push
286806f38c66SRichard Henderson #pragma GCC diagnostic ignored "-Wtype-limits"
286906f38c66SRichard Henderson 
287006f38c66SRichard Henderson     /* Add any HI_COMMPAGE not covered by reserved_va. */
287106f38c66SRichard Henderson     if (reserved_va < HI_COMMPAGE) {
287206f38c66SRichard Henderson         ga->bounds[n][0] = HI_COMMPAGE & qemu_host_page_mask;
287306f38c66SRichard Henderson         ga->bounds[n][1] = HI_COMMPAGE + TARGET_PAGE_SIZE - 1;
287406f38c66SRichard Henderson         n++;
287506f38c66SRichard Henderson     }
287606f38c66SRichard Henderson 
287706f38c66SRichard Henderson #pragma GCC diagnostic pop
287806f38c66SRichard Henderson 
287906f38c66SRichard Henderson     ga->nbounds = n;
288006f38c66SRichard Henderson     return true;
288106f38c66SRichard Henderson }
288206f38c66SRichard Henderson 
2883ee947430SAlex Bennée static void pgb_fail_in_use(const char *image_name)
2884ee947430SAlex Bennée {
2885ee947430SAlex Bennée     error_report("%s: requires virtual address space that is in use "
2886ee947430SAlex Bennée                  "(omit the -B option or choose a different value)",
2887ee947430SAlex Bennée                  image_name);
2888ee947430SAlex Bennée     exit(EXIT_FAILURE);
2889ee947430SAlex Bennée }
2890ee947430SAlex Bennée 
289106f38c66SRichard Henderson static void pgb_fixed(const char *image_name, uintptr_t guest_loaddr,
289206f38c66SRichard Henderson                       uintptr_t guest_hiaddr, uintptr_t align)
2893ee947430SAlex Bennée {
289406f38c66SRichard Henderson     PGBAddrs ga;
289506f38c66SRichard Henderson     uintptr_t brk = (uintptr_t)sbrk(0);
2896ee947430SAlex Bennée 
2897ee947430SAlex Bennée     if (!QEMU_IS_ALIGNED(guest_base, align)) {
28985ca870b9SRichard Henderson         fprintf(stderr, "Requested guest base %p does not satisfy "
289906f38c66SRichard Henderson                 "host minimum alignment (0x%" PRIxPTR ")\n",
29005ca870b9SRichard Henderson                 (void *)guest_base, align);
2901ee947430SAlex Bennée         exit(EXIT_FAILURE);
2902ee947430SAlex Bennée     }
2903ee947430SAlex Bennée 
290406f38c66SRichard Henderson     if (!pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, !guest_base)
290506f38c66SRichard Henderson         || !pgb_try_mmap_set(&ga, guest_base, brk)) {
2906ee947430SAlex Bennée         pgb_fail_in_use(image_name);
2907ee947430SAlex Bennée     }
2908ee947430SAlex Bennée }
2909ee947430SAlex Bennée 
2910ad592e37SAlex Bennée /**
2911dd558855SRichard Henderson  * pgb_find_fallback:
2912ad592e37SAlex Bennée  *
2913dd558855SRichard Henderson  * This is a fallback method for finding holes in the host address space
2914dd558855SRichard Henderson  * if we don't have the benefit of being able to access /proc/self/map.
2915dd558855SRichard Henderson  * It can potentially take a very long time as we can only dumbly iterate
2916dd558855SRichard Henderson  * up the host address space seeing if the allocation would work.
2917ad592e37SAlex Bennée  */
2918dd558855SRichard Henderson static uintptr_t pgb_find_fallback(const PGBAddrs *ga, uintptr_t align,
2919dd558855SRichard Henderson                                    uintptr_t brk)
2920ad592e37SAlex Bennée {
2921dd558855SRichard Henderson     /* TODO: come up with a better estimate of how much to skip. */
2922dd558855SRichard Henderson     uintptr_t skip = sizeof(uintptr_t) == 4 ? MiB : GiB;
2923ad592e37SAlex Bennée 
2924dd558855SRichard Henderson     for (uintptr_t base = skip; ; base += skip) {
2925dd558855SRichard Henderson         base = ROUND_UP(base, align);
2926dd558855SRichard Henderson         if (pgb_try_mmap_set(ga, base, brk)) {
2927dd558855SRichard Henderson             return base;
2928dd558855SRichard Henderson         }
2929dd558855SRichard Henderson         if (base >= -skip) {
2930dd558855SRichard Henderson             return -1;
2931dd558855SRichard Henderson         }
2932dd558855SRichard Henderson     }
2933dd558855SRichard Henderson }
2934dd558855SRichard Henderson 
2935dd558855SRichard Henderson static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base,
2936dd558855SRichard Henderson                                IntervalTreeRoot *root)
2937dd558855SRichard Henderson {
2938dd558855SRichard Henderson     for (int i = ga->nbounds - 1; i >= 0; --i) {
2939dd558855SRichard Henderson         uintptr_t s = base + ga->bounds[i][0];
2940dd558855SRichard Henderson         uintptr_t l = base + ga->bounds[i][1];
2941dd558855SRichard Henderson         IntervalTreeNode *n;
2942dd558855SRichard Henderson 
2943dd558855SRichard Henderson         if (l < s) {
2944dd558855SRichard Henderson             /* Wraparound. Skip to advance S to mmap_min_addr. */
2945dd558855SRichard Henderson             return mmap_min_addr - s;
2946dd558855SRichard Henderson         }
2947dd558855SRichard Henderson 
2948dd558855SRichard Henderson         n = interval_tree_iter_first(root, s, l);
2949dd558855SRichard Henderson         if (n != NULL) {
2950dd558855SRichard Henderson             /* Conflict.  Skip to advance S to LAST + 1. */
2951dd558855SRichard Henderson             return n->last - s + 1;
2952dd558855SRichard Henderson         }
2953dd558855SRichard Henderson     }
2954dd558855SRichard Henderson     return 0;  /* success */
2955dd558855SRichard Henderson }
2956dd558855SRichard Henderson 
2957dd558855SRichard Henderson static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root,
2958dd558855SRichard Henderson                                 uintptr_t align, uintptr_t brk)
2959dd558855SRichard Henderson {
2960dd558855SRichard Henderson     uintptr_t last = mmap_min_addr;
2961dd558855SRichard Henderson     uintptr_t base, skip;
2962ad592e37SAlex Bennée 
2963ad592e37SAlex Bennée     while (true) {
2964dd558855SRichard Henderson         base = ROUND_UP(last, align);
2965dd558855SRichard Henderson         if (base < last) {
2966ad592e37SAlex Bennée             return -1;
2967ad592e37SAlex Bennée         }
2968dd558855SRichard Henderson 
2969dd558855SRichard Henderson         skip = pgb_try_itree(ga, base, root);
2970dd558855SRichard Henderson         if (skip == 0) {
2971dd558855SRichard Henderson             break;
29722667e069SAlex Bennée         }
2973dd558855SRichard Henderson 
2974dd558855SRichard Henderson         last = base + skip;
2975dd558855SRichard Henderson         if (last < base) {
2976dd558855SRichard Henderson             return -1;
2977ad592e37SAlex Bennée         }
2978ad592e37SAlex Bennée     }
2979ad592e37SAlex Bennée 
2980dd558855SRichard Henderson     /*
2981dd558855SRichard Henderson      * We've chosen 'base' based on holes in the interval tree,
2982dd558855SRichard Henderson      * but we don't yet know if it is a valid host address.
2983dd558855SRichard Henderson      * Because it is the first matching hole, if the host addresses
2984dd558855SRichard Henderson      * are invalid we know there are no further matches.
2985dd558855SRichard Henderson      */
2986dd558855SRichard Henderson     return pgb_try_mmap_set(ga, base, brk) ? base : -1;
2987dd558855SRichard Henderson }
2988dd558855SRichard Henderson 
2989dd558855SRichard Henderson static void pgb_dynamic(const char *image_name, uintptr_t guest_loaddr,
2990dd558855SRichard Henderson                         uintptr_t guest_hiaddr, uintptr_t align)
2991ee947430SAlex Bennée {
2992dd558855SRichard Henderson     IntervalTreeRoot *root;
2993dd558855SRichard Henderson     uintptr_t brk, ret;
2994dd558855SRichard Henderson     PGBAddrs ga;
2995ee947430SAlex Bennée 
2996ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_loaddr, align));
2997ee947430SAlex Bennée 
2998dd558855SRichard Henderson     /* Try the identity map first. */
2999dd558855SRichard Henderson     if (pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, true)) {
3000dd558855SRichard Henderson         brk = (uintptr_t)sbrk(0);
3001dd558855SRichard Henderson         if (pgb_try_mmap_set(&ga, 0, brk)) {
3002dd558855SRichard Henderson             guest_base = 0;
3003dd558855SRichard Henderson             return;
3004dd558855SRichard Henderson         }
3005dd558855SRichard Henderson     }
3006dd558855SRichard Henderson 
3007dd558855SRichard Henderson     /*
3008dd558855SRichard Henderson      * Rebuild the address set for non-identity map.
3009dd558855SRichard Henderson      * This differs in the mapping of the guest NULL page.
3010dd558855SRichard Henderson      */
3011dd558855SRichard Henderson     pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, false);
3012dd558855SRichard Henderson 
3013dd558855SRichard Henderson     root = read_self_maps();
3014ee947430SAlex Bennée 
3015ee947430SAlex Bennée     /* Read brk after we've read the maps, which will malloc. */
3016ee947430SAlex Bennée     brk = (uintptr_t)sbrk(0);
3017ee947430SAlex Bennée 
3018dd558855SRichard Henderson     if (!root) {
3019dd558855SRichard Henderson         ret = pgb_find_fallback(&ga, align, brk);
3020ee947430SAlex Bennée     } else {
3021ee947430SAlex Bennée         /*
3022dd558855SRichard Henderson          * Reserve the area close to the host brk.
3023dd558855SRichard Henderson          * This will be freed with the rest of the tree.
3024ee947430SAlex Bennée          */
3025dd558855SRichard Henderson         IntervalTreeNode *b = g_new0(IntervalTreeNode, 1);
3026dd558855SRichard Henderson         b->start = brk;
3027dd558855SRichard Henderson         b->last = brk + 16 * MiB - 1;
3028dd558855SRichard Henderson         interval_tree_insert(b, root);
3029dd558855SRichard Henderson 
3030dd558855SRichard Henderson         ret = pgb_find_itree(&ga, root, align, brk);
3031dd558855SRichard Henderson         free_self_maps(root);
3032ee947430SAlex Bennée     }
3033ee947430SAlex Bennée 
3034dd558855SRichard Henderson     if (ret == -1) {
3035dd558855SRichard Henderson         int w = TARGET_LONG_BITS / 4;
3036dd558855SRichard Henderson 
3037dd558855SRichard Henderson         error_report("%s: Unable to find a guest_base to satisfy all "
3038dd558855SRichard Henderson                      "guest address mapping requirements", image_name);
3039dd558855SRichard Henderson 
3040dd558855SRichard Henderson         for (int i = 0; i < ga.nbounds; ++i) {
3041dd558855SRichard Henderson             error_printf("  %0*" PRIx64 "-%0*" PRIx64 "\n",
3042dd558855SRichard Henderson                          w, (uint64_t)ga.bounds[i][0],
3043dd558855SRichard Henderson                          w, (uint64_t)ga.bounds[i][1]);
3044dd558855SRichard Henderson         }
3045ee947430SAlex Bennée         exit(EXIT_FAILURE);
3046ee947430SAlex Bennée     }
3047dd558855SRichard Henderson     guest_base = ret;
3048ee947430SAlex Bennée }
3049ee947430SAlex Bennée 
3050ee947430SAlex Bennée void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
3051ee947430SAlex Bennée                       abi_ulong guest_hiaddr)
3052dce10401SMeador Inge {
305330ab9ef2SRichard Henderson     /* In order to use host shmat, we must be able to honor SHMLBA.  */
3054ee947430SAlex Bennée     uintptr_t align = MAX(SHMLBA, qemu_host_page_size);
3055dce10401SMeador Inge 
30560c441aebSRichard Henderson     /* Sanity check the guest binary. */
30570c441aebSRichard Henderson     if (reserved_va) {
30580c441aebSRichard Henderson         if (guest_hiaddr > reserved_va) {
30590c441aebSRichard Henderson             error_report("%s: requires more than reserved virtual "
30600c441aebSRichard Henderson                          "address space (0x%" PRIx64 " > 0x%lx)",
30610c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr, reserved_va);
30620c441aebSRichard Henderson             exit(EXIT_FAILURE);
30630c441aebSRichard Henderson         }
30640c441aebSRichard Henderson     } else {
30650c441aebSRichard Henderson         if (guest_hiaddr != (uintptr_t)guest_hiaddr) {
30660c441aebSRichard Henderson             error_report("%s: requires more virtual address space "
30670c441aebSRichard Henderson                          "than the host can provide (0x%" PRIx64 ")",
30680c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr + 1);
30690c441aebSRichard Henderson             exit(EXIT_FAILURE);
30700c441aebSRichard Henderson         }
30710c441aebSRichard Henderson     }
30720c441aebSRichard Henderson 
3073ee947430SAlex Bennée     if (have_guest_base) {
307406f38c66SRichard Henderson         pgb_fixed(image_name, guest_loaddr, guest_hiaddr, align);
3075293f2060SLuke Shumaker     } else {
3076dd558855SRichard Henderson         pgb_dynamic(image_name, guest_loaddr, guest_hiaddr, align);
3077806d1021SMeador Inge     }
3078806d1021SMeador Inge 
3079ee947430SAlex Bennée     /* Reserve and initialize the commpage. */
3080ee947430SAlex Bennée     if (!init_guest_commpage()) {
308106f38c66SRichard Henderson         /* We have already probed for the commpage being free. */
308206f38c66SRichard Henderson         g_assert_not_reached();
3083dce10401SMeador Inge     }
3084dce10401SMeador Inge 
3085ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_base, align));
3086ee947430SAlex Bennée     qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space "
3087ee947430SAlex Bennée                   "@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
3088dce10401SMeador Inge }
3089dce10401SMeador Inge 
309083f990ebSRichard Henderson enum {
309183f990ebSRichard Henderson     /* The string "GNU\0" as a magic number. */
309283f990ebSRichard Henderson     GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
309383f990ebSRichard Henderson     NOTE_DATA_SZ = 1 * KiB,
309483f990ebSRichard Henderson     NOTE_NAME_SZ = 4,
309583f990ebSRichard Henderson     ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
309683f990ebSRichard Henderson };
309783f990ebSRichard Henderson 
309883f990ebSRichard Henderson /*
309983f990ebSRichard Henderson  * Process a single gnu_property entry.
310083f990ebSRichard Henderson  * Return false for error.
310183f990ebSRichard Henderson  */
310283f990ebSRichard Henderson static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
310383f990ebSRichard Henderson                                struct image_info *info, bool have_prev_type,
310483f990ebSRichard Henderson                                uint32_t *prev_type, Error **errp)
310583f990ebSRichard Henderson {
310683f990ebSRichard Henderson     uint32_t pr_type, pr_datasz, step;
310783f990ebSRichard Henderson 
310883f990ebSRichard Henderson     if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
310983f990ebSRichard Henderson         goto error_data;
311083f990ebSRichard Henderson     }
311183f990ebSRichard Henderson     datasz -= *off;
311283f990ebSRichard Henderson     data += *off / sizeof(uint32_t);
311383f990ebSRichard Henderson 
311483f990ebSRichard Henderson     if (datasz < 2 * sizeof(uint32_t)) {
311583f990ebSRichard Henderson         goto error_data;
311683f990ebSRichard Henderson     }
311783f990ebSRichard Henderson     pr_type = data[0];
311883f990ebSRichard Henderson     pr_datasz = data[1];
311983f990ebSRichard Henderson     data += 2;
312083f990ebSRichard Henderson     datasz -= 2 * sizeof(uint32_t);
312183f990ebSRichard Henderson     step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
312283f990ebSRichard Henderson     if (step > datasz) {
312383f990ebSRichard Henderson         goto error_data;
312483f990ebSRichard Henderson     }
312583f990ebSRichard Henderson 
312683f990ebSRichard Henderson     /* Properties are supposed to be unique and sorted on pr_type. */
312783f990ebSRichard Henderson     if (have_prev_type && pr_type <= *prev_type) {
312883f990ebSRichard Henderson         if (pr_type == *prev_type) {
312983f990ebSRichard Henderson             error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
313083f990ebSRichard Henderson         } else {
313183f990ebSRichard Henderson             error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
313283f990ebSRichard Henderson         }
313383f990ebSRichard Henderson         return false;
313483f990ebSRichard Henderson     }
313583f990ebSRichard Henderson     *prev_type = pr_type;
313683f990ebSRichard Henderson 
313783f990ebSRichard Henderson     if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
313883f990ebSRichard Henderson         return false;
313983f990ebSRichard Henderson     }
314083f990ebSRichard Henderson 
314183f990ebSRichard Henderson     *off += 2 * sizeof(uint32_t) + step;
314283f990ebSRichard Henderson     return true;
314383f990ebSRichard Henderson 
314483f990ebSRichard Henderson  error_data:
314583f990ebSRichard Henderson     error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
314683f990ebSRichard Henderson     return false;
314783f990ebSRichard Henderson }
314883f990ebSRichard Henderson 
314983f990ebSRichard Henderson /* Process NT_GNU_PROPERTY_TYPE_0. */
31503bd02386SRichard Henderson static bool parse_elf_properties(const ImageSource *src,
315183f990ebSRichard Henderson                                  struct image_info *info,
315283f990ebSRichard Henderson                                  const struct elf_phdr *phdr,
315383f990ebSRichard Henderson                                  Error **errp)
315483f990ebSRichard Henderson {
315583f990ebSRichard Henderson     union {
315683f990ebSRichard Henderson         struct elf_note nhdr;
315783f990ebSRichard Henderson         uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
315883f990ebSRichard Henderson     } note;
315983f990ebSRichard Henderson 
316083f990ebSRichard Henderson     int n, off, datasz;
316183f990ebSRichard Henderson     bool have_prev_type;
316283f990ebSRichard Henderson     uint32_t prev_type;
316383f990ebSRichard Henderson 
316483f990ebSRichard Henderson     /* Unless the arch requires properties, ignore them. */
316583f990ebSRichard Henderson     if (!ARCH_USE_GNU_PROPERTY) {
316683f990ebSRichard Henderson         return true;
316783f990ebSRichard Henderson     }
316883f990ebSRichard Henderson 
316983f990ebSRichard Henderson     /* If the properties are crazy large, that's too bad. */
317083f990ebSRichard Henderson     n = phdr->p_filesz;
317183f990ebSRichard Henderson     if (n > sizeof(note)) {
317283f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too large");
317383f990ebSRichard Henderson         return false;
317483f990ebSRichard Henderson     }
317583f990ebSRichard Henderson     if (n < sizeof(note.nhdr)) {
317683f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too small");
317783f990ebSRichard Henderson         return false;
317883f990ebSRichard Henderson     }
317983f990ebSRichard Henderson 
31803bd02386SRichard Henderson     if (!imgsrc_read(&note, phdr->p_offset, n, src, errp)) {
318183f990ebSRichard Henderson         return false;
318283f990ebSRichard Henderson     }
318383f990ebSRichard Henderson 
318483f990ebSRichard Henderson     /*
318583f990ebSRichard Henderson      * The contents of a valid PT_GNU_PROPERTY is a sequence
318683f990ebSRichard Henderson      * of uint32_t -- swap them all now.
318783f990ebSRichard Henderson      */
318883f990ebSRichard Henderson #ifdef BSWAP_NEEDED
318983f990ebSRichard Henderson     for (int i = 0; i < n / 4; i++) {
319083f990ebSRichard Henderson         bswap32s(note.data + i);
319183f990ebSRichard Henderson     }
319283f990ebSRichard Henderson #endif
319383f990ebSRichard Henderson 
319483f990ebSRichard Henderson     /*
319583f990ebSRichard Henderson      * Note that nhdr is 3 words, and that the "name" described by namesz
319683f990ebSRichard Henderson      * immediately follows nhdr and is thus at the 4th word.  Further, all
319783f990ebSRichard Henderson      * of the inputs to the kernel's round_up are multiples of 4.
319883f990ebSRichard Henderson      */
319983f990ebSRichard Henderson     if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
320083f990ebSRichard Henderson         note.nhdr.n_namesz != NOTE_NAME_SZ ||
320183f990ebSRichard Henderson         note.data[3] != GNU0_MAGIC) {
320283f990ebSRichard Henderson         error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
320383f990ebSRichard Henderson         return false;
320483f990ebSRichard Henderson     }
320583f990ebSRichard Henderson     off = sizeof(note.nhdr) + NOTE_NAME_SZ;
320683f990ebSRichard Henderson 
320783f990ebSRichard Henderson     datasz = note.nhdr.n_descsz + off;
320883f990ebSRichard Henderson     if (datasz > n) {
320983f990ebSRichard Henderson         error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
321083f990ebSRichard Henderson         return false;
321183f990ebSRichard Henderson     }
321283f990ebSRichard Henderson 
321383f990ebSRichard Henderson     have_prev_type = false;
321483f990ebSRichard Henderson     prev_type = 0;
321583f990ebSRichard Henderson     while (1) {
321683f990ebSRichard Henderson         if (off == datasz) {
321783f990ebSRichard Henderson             return true;  /* end, exit ok */
321883f990ebSRichard Henderson         }
321983f990ebSRichard Henderson         if (!parse_elf_property(note.data, &off, datasz, info,
322083f990ebSRichard Henderson                                 have_prev_type, &prev_type, errp)) {
322183f990ebSRichard Henderson             return false;
322283f990ebSRichard Henderson         }
322383f990ebSRichard Henderson         have_prev_type = true;
322483f990ebSRichard Henderson     }
322583f990ebSRichard Henderson }
322683f990ebSRichard Henderson 
32273bd02386SRichard Henderson /**
32283bd02386SRichard Henderson  * load_elf_image: Load an ELF image into the address space.
32293bd02386SRichard Henderson  * @image_name: the filename of the image, to use in error messages.
32303bd02386SRichard Henderson  * @src: the ImageSource from which to read.
32313bd02386SRichard Henderson  * @info: info collected from the loaded image.
32323bd02386SRichard Henderson  * @ehdr: the ELF header, not yet bswapped.
32333bd02386SRichard Henderson  * @pinterp_name: record any PT_INTERP string found.
32343bd02386SRichard Henderson  *
32353bd02386SRichard Henderson  * On return: @info values will be filled in, as necessary or available.
32363bd02386SRichard Henderson  */
323731e31b8aSbellard 
32383bd02386SRichard Henderson static void load_elf_image(const char *image_name, const ImageSource *src,
323940d487eeSRichard Henderson                            struct image_info *info, struct elfhdr *ehdr,
32403bd02386SRichard Henderson                            char **pinterp_name)
324131e31b8aSbellard {
32423bd02386SRichard Henderson     g_autofree struct elf_phdr *phdr = NULL;
32438e62a717SRichard Henderson     abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
32443bd02386SRichard Henderson     int i, prot_exec;
3245c7f17e7bSRichard Henderson     Error *err = NULL;
324631e31b8aSbellard 
32473bd02386SRichard Henderson     /*
32483bd02386SRichard Henderson      * First of all, some simple consistency checks.
32493bd02386SRichard Henderson      * Note that we rely on the bswapped ehdr staying in bprm_buf,
32503bd02386SRichard Henderson      * for later use by load_elf_binary and create_elf_tables.
32513bd02386SRichard Henderson      */
32523bd02386SRichard Henderson     if (!imgsrc_read(ehdr, 0, sizeof(*ehdr), src, &err)) {
32533bd02386SRichard Henderson         goto exit_errmsg;
32543bd02386SRichard Henderson     }
32558e62a717SRichard Henderson     if (!elf_check_ident(ehdr)) {
3256c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
32578e62a717SRichard Henderson         goto exit_errmsg;
32588e62a717SRichard Henderson     }
32598e62a717SRichard Henderson     bswap_ehdr(ehdr);
32608e62a717SRichard Henderson     if (!elf_check_ehdr(ehdr)) {
3261c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
32628e62a717SRichard Henderson         goto exit_errmsg;
326331e31b8aSbellard     }
326431e31b8aSbellard 
32653bd02386SRichard Henderson     phdr = imgsrc_read_alloc(ehdr->e_phoff,
32663bd02386SRichard Henderson                              ehdr->e_phnum * sizeof(struct elf_phdr),
32673bd02386SRichard Henderson                              src, &err);
32683bd02386SRichard Henderson     if (phdr == NULL) {
32693bd02386SRichard Henderson         goto exit_errmsg;
327031e31b8aSbellard     }
32718e62a717SRichard Henderson     bswap_phdr(phdr, ehdr->e_phnum);
327209bfb054Sbellard 
32731af02e83SMike Frysinger     info->nsegs = 0;
32741af02e83SMike Frysinger     info->pt_dynamic_addr = 0;
32751af02e83SMike Frysinger 
327698c1076cSAlex Bennée     mmap_lock();
327798c1076cSAlex Bennée 
32788a1a5274SRichard Henderson     /*
32798a1a5274SRichard Henderson      * Find the maximum size of the image and allocate an appropriate
32808a1a5274SRichard Henderson      * amount of memory to handle that.  Locate the interpreter, if any.
32818a1a5274SRichard Henderson      */
3282682674b8SRichard Henderson     loaddr = -1, hiaddr = 0;
328333143c44SLaurent Vivier     info->alignment = 0;
3284872f3d04SRichard Henderson     info->exec_stack = EXSTACK_DEFAULT;
32858e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; ++i) {
32864d9d535aSRichard Henderson         struct elf_phdr *eppnt = phdr + i;
32874d9d535aSRichard Henderson         if (eppnt->p_type == PT_LOAD) {
32884d9d535aSRichard Henderson             abi_ulong a = eppnt->p_vaddr - eppnt->p_offset;
3289682674b8SRichard Henderson             if (a < loaddr) {
3290682674b8SRichard Henderson                 loaddr = a;
3291682674b8SRichard Henderson             }
3292a3a67f54SRichard Henderson             a = eppnt->p_vaddr + eppnt->p_memsz - 1;
3293682674b8SRichard Henderson             if (a > hiaddr) {
3294682674b8SRichard Henderson                 hiaddr = a;
3295682674b8SRichard Henderson             }
32961af02e83SMike Frysinger             ++info->nsegs;
32974d9d535aSRichard Henderson             info->alignment |= eppnt->p_align;
32988a1a5274SRichard Henderson         } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
32998a1a5274SRichard Henderson             g_autofree char *interp_name = NULL;
33008a1a5274SRichard Henderson 
33018a1a5274SRichard Henderson             if (*pinterp_name) {
3302c7f17e7bSRichard Henderson                 error_setg(&err, "Multiple PT_INTERP entries");
33038a1a5274SRichard Henderson                 goto exit_errmsg;
33048a1a5274SRichard Henderson             }
3305c7f17e7bSRichard Henderson 
33063bd02386SRichard Henderson             interp_name = imgsrc_read_alloc(eppnt->p_offset, eppnt->p_filesz,
33073bd02386SRichard Henderson                                             src, &err);
33083bd02386SRichard Henderson             if (interp_name == NULL) {
33093bd02386SRichard Henderson                 goto exit_errmsg;
33108a1a5274SRichard Henderson             }
33118a1a5274SRichard Henderson             if (interp_name[eppnt->p_filesz - 1] != 0) {
3312c7f17e7bSRichard Henderson                 error_setg(&err, "Invalid PT_INTERP entry");
33138a1a5274SRichard Henderson                 goto exit_errmsg;
33148a1a5274SRichard Henderson             }
33158a1a5274SRichard Henderson             *pinterp_name = g_steal_pointer(&interp_name);
331683f990ebSRichard Henderson         } else if (eppnt->p_type == PT_GNU_PROPERTY) {
33173bd02386SRichard Henderson             if (!parse_elf_properties(src, info, eppnt, &err)) {
331883f990ebSRichard Henderson                 goto exit_errmsg;
331983f990ebSRichard Henderson             }
3320872f3d04SRichard Henderson         } else if (eppnt->p_type == PT_GNU_STACK) {
3321872f3d04SRichard Henderson             info->exec_stack = eppnt->p_flags & PF_X;
3322682674b8SRichard Henderson         }
3323682674b8SRichard Henderson     }
3324682674b8SRichard Henderson 
33251ea06dedSRichard Henderson     load_addr = loaddr;
33261ea06dedSRichard Henderson 
33276fd59449SRichard Henderson     if (pinterp_name != NULL) {
33286fd59449SRichard Henderson         if (ehdr->e_type == ET_EXEC) {
33296fd59449SRichard Henderson             /*
33306fd59449SRichard Henderson              * Make sure that the low address does not conflict with
33316fd59449SRichard Henderson              * MMAP_MIN_ADDR or the QEMU application itself.
33326fd59449SRichard Henderson              */
33336fd59449SRichard Henderson             probe_guest_base(image_name, loaddr, hiaddr);
3334ee947430SAlex Bennée         } else {
33351ea06dedSRichard Henderson             abi_ulong align;
33361ea06dedSRichard Henderson 
3337ee947430SAlex Bennée             /*
3338ee947430SAlex Bennée              * The binary is dynamic, but we still need to
3339ee947430SAlex Bennée              * select guest_base.  In this case we pass a size.
3340ee947430SAlex Bennée              */
3341ee947430SAlex Bennée             probe_guest_base(image_name, 0, hiaddr - loaddr);
33421ea06dedSRichard Henderson 
33431ea06dedSRichard Henderson             /*
33441ea06dedSRichard Henderson              * Avoid collision with the loader by providing a different
33451ea06dedSRichard Henderson              * default load address.
33461ea06dedSRichard Henderson              */
33471ea06dedSRichard Henderson             load_addr += elf_et_dyn_base;
33481ea06dedSRichard Henderson 
33491ea06dedSRichard Henderson             /*
33501ea06dedSRichard Henderson              * TODO: Better support for mmap alignment is desirable.
33511ea06dedSRichard Henderson              * Since we do not have complete control over the guest
33521ea06dedSRichard Henderson              * address space, we prefer the kernel to choose some address
33531ea06dedSRichard Henderson              * rather than force the use of LOAD_ADDR via MAP_FIXED.
33541ea06dedSRichard Henderson              * But without MAP_FIXED we cannot guarantee alignment,
33551ea06dedSRichard Henderson              * only suggest it.
33561ea06dedSRichard Henderson              */
33571ea06dedSRichard Henderson             align = pow2ceil(info->alignment);
33581ea06dedSRichard Henderson             if (align) {
33591ea06dedSRichard Henderson                 load_addr &= -align;
33601ea06dedSRichard Henderson             }
33616fd59449SRichard Henderson         }
33626fd59449SRichard Henderson     }
33636fd59449SRichard Henderson 
33646fd59449SRichard Henderson     /*
33656fd59449SRichard Henderson      * Reserve address space for all of this.
33666fd59449SRichard Henderson      *
3367ad25051bSRichard Henderson      * In the case of ET_EXEC, we supply MAP_FIXED_NOREPLACE so that we get
3368ad25051bSRichard Henderson      * exactly the address range that is required.  Without reserved_va,
3369ad25051bSRichard Henderson      * the guest address space is not isolated.  We have attempted to avoid
3370ad25051bSRichard Henderson      * conflict with the host program itself via probe_guest_base, but using
3371ad25051bSRichard Henderson      * MAP_FIXED_NOREPLACE instead of MAP_FIXED provides an extra check.
33726fd59449SRichard Henderson      *
33736fd59449SRichard Henderson      * Otherwise this is ET_DYN, and we are searching for a location
33746fd59449SRichard Henderson      * that can hold the memory space required.  If the image is
33751ea06dedSRichard Henderson      * pre-linked, LOAD_ADDR will be non-zero, and the kernel should
33766fd59449SRichard Henderson      * honor that address if it happens to be free.
33776fd59449SRichard Henderson      *
33786fd59449SRichard Henderson      * In both cases, we will overwrite pages in this range with mappings
33796fd59449SRichard Henderson      * from the executable.
33806fd59449SRichard Henderson      */
33811ea06dedSRichard Henderson     load_addr = target_mmap(load_addr, (size_t)hiaddr - loaddr + 1, PROT_NONE,
33826fd59449SRichard Henderson                             MAP_PRIVATE | MAP_ANON | MAP_NORESERVE |
3383ad25051bSRichard Henderson                             (ehdr->e_type == ET_EXEC ? MAP_FIXED_NOREPLACE : 0),
338409bfb054Sbellard                             -1, 0);
3385682674b8SRichard Henderson     if (load_addr == -1) {
3386c7f17e7bSRichard Henderson         goto exit_mmap;
338709bfb054Sbellard     }
3388682674b8SRichard Henderson     load_bias = load_addr - loaddr;
338909bfb054Sbellard 
3390a99856cdSChristophe Lyon     if (elf_is_fdpic(ehdr)) {
33911af02e83SMike Frysinger         struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
33927267c094SAnthony Liguori             g_malloc(sizeof(*loadsegs) * info->nsegs);
33931af02e83SMike Frysinger 
33941af02e83SMike Frysinger         for (i = 0; i < ehdr->e_phnum; ++i) {
33951af02e83SMike Frysinger             switch (phdr[i].p_type) {
33961af02e83SMike Frysinger             case PT_DYNAMIC:
33971af02e83SMike Frysinger                 info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
33981af02e83SMike Frysinger                 break;
33991af02e83SMike Frysinger             case PT_LOAD:
34001af02e83SMike Frysinger                 loadsegs->addr = phdr[i].p_vaddr + load_bias;
34011af02e83SMike Frysinger                 loadsegs->p_vaddr = phdr[i].p_vaddr;
34021af02e83SMike Frysinger                 loadsegs->p_memsz = phdr[i].p_memsz;
34031af02e83SMike Frysinger                 ++loadsegs;
34041af02e83SMike Frysinger                 break;
34051af02e83SMike Frysinger             }
34061af02e83SMike Frysinger         }
34071af02e83SMike Frysinger     }
34081af02e83SMike Frysinger 
34098e62a717SRichard Henderson     info->load_bias = load_bias;
3410dc12567aSJosh Kunz     info->code_offset = load_bias;
3411dc12567aSJosh Kunz     info->data_offset = load_bias;
34128e62a717SRichard Henderson     info->load_addr = load_addr;
34138e62a717SRichard Henderson     info->entry = ehdr->e_entry + load_bias;
34148e62a717SRichard Henderson     info->start_code = -1;
34158e62a717SRichard Henderson     info->end_code = 0;
34168e62a717SRichard Henderson     info->start_data = -1;
34178e62a717SRichard Henderson     info->end_data = 0;
34181f356e8cSHelge Deller     /* Usual start for brk is after all sections of the main executable. */
3419aec338d6SRichard Henderson     info->brk = TARGET_PAGE_ALIGN(hiaddr + load_bias);
3420d8fd2954SPaul Brook     info->elf_flags = ehdr->e_flags;
34218e62a717SRichard Henderson 
3422e8384b37SRichard Henderson     prot_exec = PROT_EXEC;
3423e8384b37SRichard Henderson #ifdef TARGET_AARCH64
3424e8384b37SRichard Henderson     /*
3425e8384b37SRichard Henderson      * If the BTI feature is present, this indicates that the executable
3426e8384b37SRichard Henderson      * pages of the startup binary should be mapped with PROT_BTI, so that
3427e8384b37SRichard Henderson      * branch targets are enforced.
3428e8384b37SRichard Henderson      *
3429e8384b37SRichard Henderson      * The startup binary is either the interpreter or the static executable.
3430e8384b37SRichard Henderson      * The interpreter is responsible for all pages of a dynamic executable.
3431e8384b37SRichard Henderson      *
3432e8384b37SRichard Henderson      * Elf notes are backward compatible to older cpus.
3433e8384b37SRichard Henderson      * Do not enable BTI unless it is supported.
3434e8384b37SRichard Henderson      */
3435e8384b37SRichard Henderson     if ((info->note_flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
3436e8384b37SRichard Henderson         && (pinterp_name == NULL || *pinterp_name == 0)
3437e8384b37SRichard Henderson         && cpu_isar_feature(aa64_bti, ARM_CPU(thread_cpu))) {
3438e8384b37SRichard Henderson         prot_exec |= TARGET_PROT_BTI;
3439e8384b37SRichard Henderson     }
3440e8384b37SRichard Henderson #endif
3441e8384b37SRichard Henderson 
34428e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; i++) {
34438e62a717SRichard Henderson         struct elf_phdr *eppnt = phdr + i;
344431e31b8aSbellard         if (eppnt->p_type == PT_LOAD) {
34455f4e5b34SRichard Henderson             abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
344631e31b8aSbellard             int elf_prot = 0;
344731e31b8aSbellard 
3448e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_R) {
3449e5eaf570SRichard Henderson                 elf_prot |= PROT_READ;
3450e5eaf570SRichard Henderson             }
3451e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_W) {
3452e5eaf570SRichard Henderson                 elf_prot |= PROT_WRITE;
3453e5eaf570SRichard Henderson             }
3454e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_X) {
3455e8384b37SRichard Henderson                 elf_prot |= prot_exec;
3456e5eaf570SRichard Henderson             }
345731e31b8aSbellard 
3458682674b8SRichard Henderson             vaddr = load_bias + eppnt->p_vaddr;
3459e3d97d5cSRichard Henderson             vaddr_po = vaddr & ~TARGET_PAGE_MASK;
3460e3d97d5cSRichard Henderson             vaddr_ps = vaddr & TARGET_PAGE_MASK;
346122d113b5SGiuseppe Musacchio 
346222d113b5SGiuseppe Musacchio             vaddr_ef = vaddr + eppnt->p_filesz;
346322d113b5SGiuseppe Musacchio             vaddr_em = vaddr + eppnt->p_memsz;
3464682674b8SRichard Henderson 
3465d87146bcSGiuseppe Musacchio             /*
346622d113b5SGiuseppe Musacchio              * Some segments may be completely empty, with a non-zero p_memsz
346722d113b5SGiuseppe Musacchio              * but no backing file segment.
3468d87146bcSGiuseppe Musacchio              */
3469d87146bcSGiuseppe Musacchio             if (eppnt->p_filesz != 0) {
34703bd02386SRichard Henderson                 error = imgsrc_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
34715f4e5b34SRichard Henderson                                     elf_prot, MAP_PRIVATE | MAP_FIXED,
34723bd02386SRichard Henderson                                     src, eppnt->p_offset - vaddr_po);
3473e89f07d3Spbrook                 if (error == -1) {
3474c7f17e7bSRichard Henderson                     goto exit_mmap;
347531e31b8aSbellard                 }
34765f4e5b34SRichard Henderson             }
347731e31b8aSbellard 
34785f4e5b34SRichard Henderson             /* If the load segment requests extra zeros (e.g. bss), map it. */
34795f4e5b34SRichard Henderson             if (vaddr_ef < vaddr_em &&
3480e6e66b03SRichard Henderson                 !zero_bss(vaddr_ef, vaddr_em, elf_prot, &err)) {
3481e6e66b03SRichard Henderson                 goto exit_errmsg;
3482682674b8SRichard Henderson             }
34838e62a717SRichard Henderson 
34848e62a717SRichard Henderson             /* Find the full program boundaries.  */
34858e62a717SRichard Henderson             if (elf_prot & PROT_EXEC) {
34868e62a717SRichard Henderson                 if (vaddr < info->start_code) {
34878e62a717SRichard Henderson                     info->start_code = vaddr;
3488cf129f3aSRichard Henderson                 }
34898e62a717SRichard Henderson                 if (vaddr_ef > info->end_code) {
34908e62a717SRichard Henderson                     info->end_code = vaddr_ef;
34918e62a717SRichard Henderson                 }
34928e62a717SRichard Henderson             }
34938e62a717SRichard Henderson             if (elf_prot & PROT_WRITE) {
34948e62a717SRichard Henderson                 if (vaddr < info->start_data) {
34958e62a717SRichard Henderson                     info->start_data = vaddr;
34968e62a717SRichard Henderson                 }
34978e62a717SRichard Henderson                 if (vaddr_ef > info->end_data) {
34988e62a717SRichard Henderson                     info->end_data = vaddr_ef;
34998e62a717SRichard Henderson                 }
35008a045188STimothy E Baldwin             }
35015dd0db52SStefan Markovic #ifdef TARGET_MIPS
35025dd0db52SStefan Markovic         } else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
35035dd0db52SStefan Markovic             Mips_elf_abiflags_v0 abiflags;
35043bd02386SRichard Henderson 
35053bd02386SRichard Henderson             if (!imgsrc_read(&abiflags, eppnt->p_offset, sizeof(abiflags),
35063bd02386SRichard Henderson                              src, &err)) {
35075dd0db52SStefan Markovic                 goto exit_errmsg;
35085dd0db52SStefan Markovic             }
35095dd0db52SStefan Markovic             bswap_mips_abiflags(&abiflags);
3510c94cb6c9SStefan Markovic             info->fp_abi = abiflags.fp_abi;
35115dd0db52SStefan Markovic #endif
35128e62a717SRichard Henderson         }
35138e62a717SRichard Henderson     }
35148e62a717SRichard Henderson 
35158e62a717SRichard Henderson     if (info->end_data == 0) {
35168e62a717SRichard Henderson         info->start_data = info->end_code;
35178e62a717SRichard Henderson         info->end_data = info->end_code;
351831e31b8aSbellard     }
351931e31b8aSbellard 
3520682674b8SRichard Henderson     if (qemu_log_enabled()) {
352186cf82dcSRichard Henderson         load_symbols(ehdr, src, load_bias);
3522682674b8SRichard Henderson     }
352331e31b8aSbellard 
35243bd02386SRichard Henderson     debuginfo_report_elf(image_name, src->fd, load_bias);
35257c10cb38SIlya Leoshkevich 
352698c1076cSAlex Bennée     mmap_unlock();
352798c1076cSAlex Bennée 
35283bd02386SRichard Henderson     close(src->fd);
35298e62a717SRichard Henderson     return;
353031e31b8aSbellard 
3531c7f17e7bSRichard Henderson  exit_mmap:
3532c7f17e7bSRichard Henderson     error_setg_errno(&err, errno, "Error mapping file");
3533c7f17e7bSRichard Henderson     goto exit_errmsg;
35348e62a717SRichard Henderson  exit_errmsg:
3535c7f17e7bSRichard Henderson     error_reportf_err(err, "%s: ", image_name);
35368e62a717SRichard Henderson     exit(-1);
35378e62a717SRichard Henderson }
35388e62a717SRichard Henderson 
35398e62a717SRichard Henderson static void load_elf_interp(const char *filename, struct image_info *info,
35408e62a717SRichard Henderson                             char bprm_buf[BPRM_BUF_SIZE])
35418e62a717SRichard Henderson {
354240d487eeSRichard Henderson     struct elfhdr ehdr;
35433bd02386SRichard Henderson     ImageSource src;
35448e62a717SRichard Henderson     int fd, retval;
3545808f6563SRichard Henderson     Error *err = NULL;
35468e62a717SRichard Henderson 
35478e62a717SRichard Henderson     fd = open(path(filename), O_RDONLY);
35488e62a717SRichard Henderson     if (fd < 0) {
3549808f6563SRichard Henderson         error_setg_file_open(&err, errno, filename);
3550808f6563SRichard Henderson         error_report_err(err);
3551808f6563SRichard Henderson         exit(-1);
35528e62a717SRichard Henderson     }
35538e62a717SRichard Henderson 
35548e62a717SRichard Henderson     retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
35558e62a717SRichard Henderson     if (retval < 0) {
3556808f6563SRichard Henderson         error_setg_errno(&err, errno, "Error reading file header");
3557808f6563SRichard Henderson         error_reportf_err(err, "%s: ", filename);
3558808f6563SRichard Henderson         exit(-1);
35598e62a717SRichard Henderson     }
3560808f6563SRichard Henderson 
35613bd02386SRichard Henderson     src.fd = fd;
35623bd02386SRichard Henderson     src.cache = bprm_buf;
35633bd02386SRichard Henderson     src.cache_size = retval;
35648e62a717SRichard Henderson 
35653bd02386SRichard Henderson     load_elf_image(filename, &src, info, &ehdr, NULL);
356631e31b8aSbellard }
356731e31b8aSbellard 
3568c40f621aSRichard Henderson #ifdef VDSO_HEADER
3569c40f621aSRichard Henderson #include VDSO_HEADER
3570c40f621aSRichard Henderson #define  vdso_image_info()  &vdso_image_info
3571c40f621aSRichard Henderson #else
3572c40f621aSRichard Henderson #define  vdso_image_info()  NULL
3573c40f621aSRichard Henderson #endif
3574c40f621aSRichard Henderson 
3575c40f621aSRichard Henderson static void load_elf_vdso(struct image_info *info, const VdsoImageInfo *vdso)
3576c40f621aSRichard Henderson {
3577c40f621aSRichard Henderson     ImageSource src;
3578c40f621aSRichard Henderson     struct elfhdr ehdr;
3579c40f621aSRichard Henderson     abi_ulong load_bias, load_addr;
3580c40f621aSRichard Henderson 
3581c40f621aSRichard Henderson     src.fd = -1;
3582c40f621aSRichard Henderson     src.cache = vdso->image;
3583c40f621aSRichard Henderson     src.cache_size = vdso->image_size;
3584c40f621aSRichard Henderson 
3585c40f621aSRichard Henderson     load_elf_image("<internal-vdso>", &src, info, &ehdr, NULL);
3586c40f621aSRichard Henderson     load_addr = info->load_addr;
3587c40f621aSRichard Henderson     load_bias = info->load_bias;
3588c40f621aSRichard Henderson 
3589c40f621aSRichard Henderson     /*
3590c40f621aSRichard Henderson      * We need to relocate the VDSO image.  The one built into the kernel
3591c40f621aSRichard Henderson      * is built for a fixed address.  The one built for QEMU is not, since
3592c40f621aSRichard Henderson      * that requires close control of the guest address space.
3593c40f621aSRichard Henderson      * We pre-processed the image to locate all of the addresses that need
3594c40f621aSRichard Henderson      * to be updated.
3595c40f621aSRichard Henderson      */
3596c40f621aSRichard Henderson     for (unsigned i = 0, n = vdso->reloc_count; i < n; i++) {
3597c40f621aSRichard Henderson         abi_ulong *addr = g2h_untagged(load_addr + vdso->relocs[i]);
3598c40f621aSRichard Henderson         *addr = tswapal(tswapal(*addr) + load_bias);
3599c40f621aSRichard Henderson     }
3600c40f621aSRichard Henderson 
3601c40f621aSRichard Henderson     /* Install signal trampolines, if present. */
3602c40f621aSRichard Henderson     if (vdso->sigreturn_ofs) {
3603c40f621aSRichard Henderson         default_sigreturn = load_addr + vdso->sigreturn_ofs;
3604c40f621aSRichard Henderson     }
3605c40f621aSRichard Henderson     if (vdso->rt_sigreturn_ofs) {
3606c40f621aSRichard Henderson         default_rt_sigreturn = load_addr + vdso->rt_sigreturn_ofs;
3607c40f621aSRichard Henderson     }
3608c40f621aSRichard Henderson 
3609c40f621aSRichard Henderson     /* Remove write from VDSO segment. */
3610c40f621aSRichard Henderson     target_mprotect(info->start_data, info->end_data - info->start_data,
3611c40f621aSRichard Henderson                     PROT_READ | PROT_EXEC);
3612c40f621aSRichard Henderson }
3613c40f621aSRichard Henderson 
361449918a75Spbrook static int symfind(const void *s0, const void *s1)
361549918a75Spbrook {
361649918a75Spbrook     struct elf_sym *sym = (struct elf_sym *)s1;
3617b6235a75SRichard Henderson     __typeof(sym->st_value) addr = *(uint64_t *)s0;
361849918a75Spbrook     int result = 0;
3619b6235a75SRichard Henderson 
3620c7c530cdSStefan Weil     if (addr < sym->st_value) {
362149918a75Spbrook         result = -1;
3622c7c530cdSStefan Weil     } else if (addr >= sym->st_value + sym->st_size) {
362349918a75Spbrook         result = 1;
362449918a75Spbrook     }
362549918a75Spbrook     return result;
362649918a75Spbrook }
362749918a75Spbrook 
3628b6235a75SRichard Henderson static const char *lookup_symbolxx(struct syminfo *s, uint64_t orig_addr)
362949918a75Spbrook {
363049918a75Spbrook #if ELF_CLASS == ELFCLASS32
363149918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf32;
363249918a75Spbrook #else
363349918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf64;
363449918a75Spbrook #endif
363549918a75Spbrook 
363649918a75Spbrook     // binary search
363749918a75Spbrook     struct elf_sym *sym;
363849918a75Spbrook 
3639c7c530cdSStefan Weil     sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
36407cba04f6SBlue Swirl     if (sym != NULL) {
364149918a75Spbrook         return s->disas_strtab + sym->st_name;
364249918a75Spbrook     }
364349918a75Spbrook 
364449918a75Spbrook     return "";
364549918a75Spbrook }
364649918a75Spbrook 
364749918a75Spbrook /* FIXME: This should use elf_ops.h  */
364849918a75Spbrook static int symcmp(const void *s0, const void *s1)
364949918a75Spbrook {
365049918a75Spbrook     struct elf_sym *sym0 = (struct elf_sym *)s0;
365149918a75Spbrook     struct elf_sym *sym1 = (struct elf_sym *)s1;
365249918a75Spbrook     return (sym0->st_value < sym1->st_value)
365349918a75Spbrook         ? -1
365449918a75Spbrook         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
365549918a75Spbrook }
365649918a75Spbrook 
3657689f936fSbellard /* Best attempt to load symbols from this ELF object. */
365886cf82dcSRichard Henderson static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
365986cf82dcSRichard Henderson                          abi_ulong load_bias)
3660689f936fSbellard {
3661682674b8SRichard Henderson     int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
366286cf82dcSRichard Henderson     g_autofree struct elf_shdr *shdr = NULL;
3663b9475279SCédric VINCENT     char *strings = NULL;
366486cf82dcSRichard Henderson     struct elf_sym *syms = NULL;
366586cf82dcSRichard Henderson     struct elf_sym *new_syms;
366686cf82dcSRichard Henderson     uint64_t segsz;
366731e31b8aSbellard 
3668682674b8SRichard Henderson     shnum = hdr->e_shnum;
366986cf82dcSRichard Henderson     shdr = imgsrc_read_alloc(hdr->e_shoff, shnum * sizeof(struct elf_shdr),
367086cf82dcSRichard Henderson                              src, NULL);
367186cf82dcSRichard Henderson     if (shdr == NULL) {
3672689f936fSbellard         return;
3673682674b8SRichard Henderson     }
3674682674b8SRichard Henderson 
3675682674b8SRichard Henderson     bswap_shdr(shdr, shnum);
3676682674b8SRichard Henderson     for (i = 0; i < shnum; ++i) {
3677682674b8SRichard Henderson         if (shdr[i].sh_type == SHT_SYMTAB) {
3678682674b8SRichard Henderson             sym_idx = i;
3679682674b8SRichard Henderson             str_idx = shdr[i].sh_link;
3680689f936fSbellard             goto found;
3681689f936fSbellard         }
3682689f936fSbellard     }
3683682674b8SRichard Henderson 
3684682674b8SRichard Henderson     /* There will be no symbol table if the file was stripped.  */
3685682674b8SRichard Henderson     return;
3686689f936fSbellard 
3687689f936fSbellard  found:
3688689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them.  */
3689682674b8SRichard Henderson 
36901e06262dSPeter Maydell     segsz = shdr[str_idx].sh_size;
369186cf82dcSRichard Henderson     strings = g_try_malloc(segsz);
369286cf82dcSRichard Henderson     if (!strings) {
369386cf82dcSRichard Henderson         goto give_up;
369486cf82dcSRichard Henderson     }
369586cf82dcSRichard Henderson     if (!imgsrc_read(strings, shdr[str_idx].sh_offset, segsz, src, NULL)) {
3696b9475279SCédric VINCENT         goto give_up;
3697682674b8SRichard Henderson     }
3698689f936fSbellard 
36991e06262dSPeter Maydell     segsz = shdr[sym_idx].sh_size;
37001e06262dSPeter Maydell     if (segsz / sizeof(struct elf_sym) > INT_MAX) {
370186cf82dcSRichard Henderson         /*
370286cf82dcSRichard Henderson          * Implausibly large symbol table: give up rather than ploughing
370386cf82dcSRichard Henderson          * on with the number of symbols calculation overflowing.
37041e06262dSPeter Maydell          */
37051e06262dSPeter Maydell         goto give_up;
37061e06262dSPeter Maydell     }
37071e06262dSPeter Maydell     nsyms = segsz / sizeof(struct elf_sym);
370886cf82dcSRichard Henderson     syms = g_try_malloc(segsz);
370986cf82dcSRichard Henderson     if (!syms) {
371086cf82dcSRichard Henderson         goto give_up;
371186cf82dcSRichard Henderson     }
371286cf82dcSRichard Henderson     if (!imgsrc_read(syms, shdr[sym_idx].sh_offset, segsz, src, NULL)) {
371386cf82dcSRichard Henderson         goto give_up;
371486cf82dcSRichard Henderson     }
371586cf82dcSRichard Henderson 
3716682674b8SRichard Henderson     for (i = 0; i < nsyms; ) {
371749918a75Spbrook         bswap_sym(syms + i);
3718682674b8SRichard Henderson         /* Throw away entries which we do not need.  */
3719682674b8SRichard Henderson         if (syms[i].st_shndx == SHN_UNDEF
3720682674b8SRichard Henderson             || syms[i].st_shndx >= SHN_LORESERVE
3721682674b8SRichard Henderson             || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
3722682674b8SRichard Henderson             if (i < --nsyms) {
372349918a75Spbrook                 syms[i] = syms[nsyms];
372449918a75Spbrook             }
3725682674b8SRichard Henderson         } else {
372649918a75Spbrook #if defined(TARGET_ARM) || defined (TARGET_MIPS)
372749918a75Spbrook             /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
372849918a75Spbrook             syms[i].st_value &= ~(target_ulong)1;
372949918a75Spbrook #endif
3730682674b8SRichard Henderson             syms[i].st_value += load_bias;
373149918a75Spbrook             i++;
373249918a75Spbrook         }
3733682674b8SRichard Henderson     }
373449918a75Spbrook 
3735b9475279SCédric VINCENT     /* No "useful" symbol.  */
3736b9475279SCédric VINCENT     if (nsyms == 0) {
3737b9475279SCédric VINCENT         goto give_up;
3738b9475279SCédric VINCENT     }
3739b9475279SCédric VINCENT 
374086cf82dcSRichard Henderson     /*
374186cf82dcSRichard Henderson      * Attempt to free the storage associated with the local symbols
374286cf82dcSRichard Henderson      * that we threw away.  Whether or not this has any effect on the
374386cf82dcSRichard Henderson      * memory allocation depends on the malloc implementation and how
374486cf82dcSRichard Henderson      * many symbols we managed to discard.
374586cf82dcSRichard Henderson      */
37460ef9ea29SPeter Maydell     new_syms = g_try_renew(struct elf_sym, syms, nsyms);
37478d79de6eSStefan Weil     if (new_syms == NULL) {
3748b9475279SCédric VINCENT         goto give_up;
37495d5c9930SRichard Henderson     }
37508d79de6eSStefan Weil     syms = new_syms;
37515d5c9930SRichard Henderson 
375249918a75Spbrook     qsort(syms, nsyms, sizeof(*syms), symcmp);
375349918a75Spbrook 
375486cf82dcSRichard Henderson     {
375586cf82dcSRichard Henderson         struct syminfo *s = g_new(struct syminfo, 1);
375686cf82dcSRichard Henderson 
375786cf82dcSRichard Henderson         s->disas_strtab = strings;
375849918a75Spbrook         s->disas_num_syms = nsyms;
375949918a75Spbrook #if ELF_CLASS == ELFCLASS32
376049918a75Spbrook         s->disas_symtab.elf32 = syms;
376149918a75Spbrook #else
376249918a75Spbrook         s->disas_symtab.elf64 = syms;
376349918a75Spbrook #endif
3764682674b8SRichard Henderson         s->lookup_symbol = lookup_symbolxx;
3765e80cfcfcSbellard         s->next = syminfos;
3766e80cfcfcSbellard         syminfos = s;
376786cf82dcSRichard Henderson     }
3768b9475279SCédric VINCENT     return;
3769b9475279SCédric VINCENT 
3770b9475279SCédric VINCENT  give_up:
37710ef9ea29SPeter Maydell     g_free(strings);
37720ef9ea29SPeter Maydell     g_free(syms);
3773689f936fSbellard }
377431e31b8aSbellard 
3775768fe76eSYunQiang Su uint32_t get_elf_eflags(int fd)
3776768fe76eSYunQiang Su {
3777768fe76eSYunQiang Su     struct elfhdr ehdr;
3778768fe76eSYunQiang Su     off_t offset;
3779768fe76eSYunQiang Su     int ret;
3780768fe76eSYunQiang Su 
3781768fe76eSYunQiang Su     /* Read ELF header */
3782768fe76eSYunQiang Su     offset = lseek(fd, 0, SEEK_SET);
3783768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3784768fe76eSYunQiang Su         return 0;
3785768fe76eSYunQiang Su     }
3786768fe76eSYunQiang Su     ret = read(fd, &ehdr, sizeof(ehdr));
3787768fe76eSYunQiang Su     if (ret < sizeof(ehdr)) {
3788768fe76eSYunQiang Su         return 0;
3789768fe76eSYunQiang Su     }
3790768fe76eSYunQiang Su     offset = lseek(fd, offset, SEEK_SET);
3791768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3792768fe76eSYunQiang Su         return 0;
3793768fe76eSYunQiang Su     }
3794768fe76eSYunQiang Su 
3795768fe76eSYunQiang Su     /* Check ELF signature */
3796768fe76eSYunQiang Su     if (!elf_check_ident(&ehdr)) {
3797768fe76eSYunQiang Su         return 0;
3798768fe76eSYunQiang Su     }
3799768fe76eSYunQiang Su 
3800768fe76eSYunQiang Su     /* check header */
3801768fe76eSYunQiang Su     bswap_ehdr(&ehdr);
3802768fe76eSYunQiang Su     if (!elf_check_ehdr(&ehdr)) {
3803768fe76eSYunQiang Su         return 0;
3804768fe76eSYunQiang Su     }
3805768fe76eSYunQiang Su 
3806768fe76eSYunQiang Su     /* return architecture id */
3807768fe76eSYunQiang Su     return ehdr.e_flags;
3808768fe76eSYunQiang Su }
3809768fe76eSYunQiang Su 
3810f0116c54SWill Newton int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
381131e31b8aSbellard {
381240d487eeSRichard Henderson     /*
381340d487eeSRichard Henderson      * We need a copy of the elf header for passing to create_elf_tables.
381440d487eeSRichard Henderson      * We will have overwritten the original when we re-use bprm->buf
381540d487eeSRichard Henderson      * while loading the interpreter.  Allocate the storage for this now
381640d487eeSRichard Henderson      * and let elf_load_image do any swapping that may be required.
381740d487eeSRichard Henderson      */
381840d487eeSRichard Henderson     struct elfhdr ehdr;
3819c40f621aSRichard Henderson     struct image_info interp_info, vdso_info;
38208e62a717SRichard Henderson     char *elf_interpreter = NULL;
382159baae9aSStefan Brüns     char *scratch;
382231e31b8aSbellard 
3823abcac736SDaniel Santos     memset(&interp_info, 0, sizeof(interp_info));
3824abcac736SDaniel Santos #ifdef TARGET_MIPS
3825abcac736SDaniel Santos     interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
3826abcac736SDaniel Santos #endif
3827abcac736SDaniel Santos 
38283bd02386SRichard Henderson     load_elf_image(bprm->filename, &bprm->src, info, &ehdr, &elf_interpreter);
382931e31b8aSbellard 
383059baae9aSStefan Brüns     /* Do this so that we can load the interpreter, if need be.  We will
383159baae9aSStefan Brüns        change some of these later */
383259baae9aSStefan Brüns     bprm->p = setup_arg_pages(bprm, info);
383359baae9aSStefan Brüns 
383459baae9aSStefan Brüns     scratch = g_new0(char, TARGET_PAGE_SIZE);
38357c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
383659baae9aSStefan Brüns         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
383759baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
38387c4ee5bcSRichard Henderson         info->file_string = bprm->p;
383959baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
384059baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
38417c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
384259baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
384359baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
38447c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
38457c4ee5bcSRichard Henderson     } else {
38467c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
38477c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
38487c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
38497c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
38507c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
38517c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
38527c4ee5bcSRichard Henderson         info->file_string = bprm->p;
38537c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
38547c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
38557c4ee5bcSRichard Henderson     }
38567c4ee5bcSRichard Henderson 
385759baae9aSStefan Brüns     g_free(scratch);
385859baae9aSStefan Brüns 
3859e5fe0c52Spbrook     if (!bprm->p) {
3860bf858897SRichard Henderson         fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
386131e31b8aSbellard         exit(-1);
38629955ffacSRichard Henderson     }
3863379f6698SPaul Brook 
38648e62a717SRichard Henderson     if (elf_interpreter) {
38658e62a717SRichard Henderson         load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
386631e31b8aSbellard 
38671f356e8cSHelge Deller         /*
38681f356e8cSHelge Deller          * While unusual because of ELF_ET_DYN_BASE, if we are unlucky
38691f356e8cSHelge Deller          * with the mappings the interpreter can be loaded above but
38701f356e8cSHelge Deller          * near the main executable, which can leave very little room
38711f356e8cSHelge Deller          * for the heap.
38721f356e8cSHelge Deller          * If the current brk has less than 16MB, use the end of the
38731f356e8cSHelge Deller          * interpreter.
38741f356e8cSHelge Deller          */
38751f356e8cSHelge Deller         if (interp_info.brk > info->brk &&
38761f356e8cSHelge Deller             interp_info.load_bias - info->brk < 16 * MiB)  {
38771f356e8cSHelge Deller             info->brk = interp_info.brk;
38781f356e8cSHelge Deller         }
38791f356e8cSHelge Deller 
38808e62a717SRichard Henderson         /* If the program interpreter is one of these two, then assume
38818e62a717SRichard Henderson            an iBCS2 image.  Otherwise assume a native linux image.  */
388231e31b8aSbellard 
38838e62a717SRichard Henderson         if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
38848e62a717SRichard Henderson             || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
38858e62a717SRichard Henderson             info->personality = PER_SVR4;
38868e62a717SRichard Henderson 
388731e31b8aSbellard             /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
38888e62a717SRichard Henderson                and some applications "depend" upon this behavior.  Since
38898e62a717SRichard Henderson                we do not have the power to recompile these, we emulate
38908e62a717SRichard Henderson                the SVr4 behavior.  Sigh.  */
38918e62a717SRichard Henderson             target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
389268754b44SPeter Maydell                         MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
389331e31b8aSbellard         }
3894c94cb6c9SStefan Markovic #ifdef TARGET_MIPS
3895c94cb6c9SStefan Markovic         info->interp_fp_abi = interp_info.fp_abi;
3896c94cb6c9SStefan Markovic #endif
38978e62a717SRichard Henderson     }
389831e31b8aSbellard 
3899db2af69dSRichard Henderson     /*
3900c40f621aSRichard Henderson      * Load a vdso if available, which will amongst other things contain the
3901c40f621aSRichard Henderson      * signal trampolines.  Otherwise, allocate a separate page for them.
3902db2af69dSRichard Henderson      */
3903c40f621aSRichard Henderson     const VdsoImageInfo *vdso = vdso_image_info();
3904c40f621aSRichard Henderson     if (vdso) {
3905c40f621aSRichard Henderson         load_elf_vdso(&vdso_info, vdso);
3906c40f621aSRichard Henderson     } else if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
3907802ae45eSLaurent Vivier         abi_long tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
3908db2af69dSRichard Henderson                                           PROT_READ | PROT_WRITE,
3909db2af69dSRichard Henderson                                           MAP_PRIVATE | MAP_ANON, -1, 0);
3910802ae45eSLaurent Vivier         if (tramp_page == -1) {
3911802ae45eSLaurent Vivier             return -errno;
3912802ae45eSLaurent Vivier         }
3913802ae45eSLaurent Vivier 
3914db2af69dSRichard Henderson         setup_sigtramp(tramp_page);
3915db2af69dSRichard Henderson         target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
3916db2af69dSRichard Henderson     }
3917db2af69dSRichard Henderson 
3918c40f621aSRichard Henderson     bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &ehdr, info,
3919c40f621aSRichard Henderson                                 elf_interpreter ? &interp_info : NULL,
3920c40f621aSRichard Henderson                                 vdso ? &vdso_info : NULL);
39218e62a717SRichard Henderson     info->start_stack = bprm->p;
39228e62a717SRichard Henderson 
39238e62a717SRichard Henderson     /* If we have an interpreter, set that as the program's entry point.
39248e78064eSRichard Henderson        Copy the load_bias as well, to help PPC64 interpret the entry
39258e62a717SRichard Henderson        point as a function descriptor.  Do this after creating elf tables
39268e62a717SRichard Henderson        so that we copy the original program entry point into the AUXV.  */
39278e62a717SRichard Henderson     if (elf_interpreter) {
39288e78064eSRichard Henderson         info->load_bias = interp_info.load_bias;
39298e62a717SRichard Henderson         info->entry = interp_info.entry;
39302b323087SPhilippe Mathieu-Daudé         g_free(elf_interpreter);
39318e62a717SRichard Henderson     }
393231e31b8aSbellard 
3933edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3934edf8e2afSMika Westerberg     bprm->core_dump = &elf_core_dump;
3935edf8e2afSMika Westerberg #endif
3936edf8e2afSMika Westerberg 
393731e31b8aSbellard     return 0;
393831e31b8aSbellard }
393931e31b8aSbellard 
3940edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3941edf8e2afSMika Westerberg /*
3942edf8e2afSMika Westerberg  * Definitions to generate Intel SVR4-like core files.
3943a2547a13SLaurent Desnogues  * These mostly have the same names as the SVR4 types with "target_elf_"
3944edf8e2afSMika Westerberg  * tacked on the front to prevent clashes with linux definitions,
3945edf8e2afSMika Westerberg  * and the typedef forms have been avoided.  This is mostly like
3946edf8e2afSMika Westerberg  * the SVR4 structure, but more Linuxy, with things that Linux does
3947edf8e2afSMika Westerberg  * not support and which gdb doesn't really use excluded.
3948edf8e2afSMika Westerberg  *
3949edf8e2afSMika Westerberg  * Fields we don't dump (their contents is zero) in linux-user qemu
3950edf8e2afSMika Westerberg  * are marked with XXX.
3951edf8e2afSMika Westerberg  *
3952edf8e2afSMika Westerberg  * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
3953edf8e2afSMika Westerberg  *
3954edf8e2afSMika Westerberg  * Porting ELF coredump for target is (quite) simple process.  First you
3955dd0a3651SNathan Froyd  * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
3956edf8e2afSMika Westerberg  * the target resides):
3957edf8e2afSMika Westerberg  *
3958edf8e2afSMika Westerberg  * #define USE_ELF_CORE_DUMP
3959edf8e2afSMika Westerberg  *
3960edf8e2afSMika Westerberg  * Next you define type of register set used for dumping.  ELF specification
3961edf8e2afSMika Westerberg  * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
3962edf8e2afSMika Westerberg  *
3963c227f099SAnthony Liguori  * typedef <target_regtype> target_elf_greg_t;
3964edf8e2afSMika Westerberg  * #define ELF_NREG <number of registers>
3965c227f099SAnthony Liguori  * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
3966edf8e2afSMika Westerberg  *
3967edf8e2afSMika Westerberg  * Last step is to implement target specific function that copies registers
3968edf8e2afSMika Westerberg  * from given cpu into just specified register set.  Prototype is:
3969edf8e2afSMika Westerberg  *
3970c227f099SAnthony Liguori  * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
39719349b4f9SAndreas Färber  *                                const CPUArchState *env);
3972edf8e2afSMika Westerberg  *
3973edf8e2afSMika Westerberg  * Parameters:
3974edf8e2afSMika Westerberg  *     regs - copy register values into here (allocated and zeroed by caller)
3975edf8e2afSMika Westerberg  *     env - copy registers from here
3976edf8e2afSMika Westerberg  *
3977edf8e2afSMika Westerberg  * Example for ARM target is provided in this file.
3978edf8e2afSMika Westerberg  */
3979edf8e2afSMika Westerberg 
3980edf8e2afSMika Westerberg /* An ELF note in memory */
3981edf8e2afSMika Westerberg struct memelfnote {
3982edf8e2afSMika Westerberg     const char *name;
3983edf8e2afSMika Westerberg     size_t     namesz;
3984edf8e2afSMika Westerberg     size_t     namesz_rounded;
3985edf8e2afSMika Westerberg     int        type;
3986edf8e2afSMika Westerberg     size_t     datasz;
398780f5ce75SLaurent Vivier     size_t     datasz_rounded;
3988edf8e2afSMika Westerberg     void       *data;
3989edf8e2afSMika Westerberg     size_t     notesz;
3990edf8e2afSMika Westerberg };
3991edf8e2afSMika Westerberg 
3992a2547a13SLaurent Desnogues struct target_elf_siginfo {
3993f8fd4fc4SPaolo Bonzini     abi_int    si_signo; /* signal number */
3994f8fd4fc4SPaolo Bonzini     abi_int    si_code;  /* extra code */
3995f8fd4fc4SPaolo Bonzini     abi_int    si_errno; /* errno */
3996edf8e2afSMika Westerberg };
3997edf8e2afSMika Westerberg 
3998a2547a13SLaurent Desnogues struct target_elf_prstatus {
3999a2547a13SLaurent Desnogues     struct target_elf_siginfo pr_info;      /* Info associated with signal */
40001ddd592fSPaolo Bonzini     abi_short          pr_cursig;    /* Current signal */
4001ca98ac83SPaolo Bonzini     abi_ulong          pr_sigpend;   /* XXX */
4002ca98ac83SPaolo Bonzini     abi_ulong          pr_sighold;   /* XXX */
4003c227f099SAnthony Liguori     target_pid_t       pr_pid;
4004c227f099SAnthony Liguori     target_pid_t       pr_ppid;
4005c227f099SAnthony Liguori     target_pid_t       pr_pgrp;
4006c227f099SAnthony Liguori     target_pid_t       pr_sid;
4007edf8e2afSMika Westerberg     struct target_timeval pr_utime;  /* XXX User time */
4008edf8e2afSMika Westerberg     struct target_timeval pr_stime;  /* XXX System time */
4009edf8e2afSMika Westerberg     struct target_timeval pr_cutime; /* XXX Cumulative user time */
4010edf8e2afSMika Westerberg     struct target_timeval pr_cstime; /* XXX Cumulative system time */
4011c227f099SAnthony Liguori     target_elf_gregset_t      pr_reg;       /* GP registers */
4012f8fd4fc4SPaolo Bonzini     abi_int            pr_fpvalid;   /* XXX */
4013edf8e2afSMika Westerberg };
4014edf8e2afSMika Westerberg 
4015edf8e2afSMika Westerberg #define ELF_PRARGSZ     (80) /* Number of chars for args */
4016edf8e2afSMika Westerberg 
4017a2547a13SLaurent Desnogues struct target_elf_prpsinfo {
4018edf8e2afSMika Westerberg     char         pr_state;       /* numeric process state */
4019edf8e2afSMika Westerberg     char         pr_sname;       /* char for pr_state */
4020edf8e2afSMika Westerberg     char         pr_zomb;        /* zombie */
4021edf8e2afSMika Westerberg     char         pr_nice;        /* nice val */
4022ca98ac83SPaolo Bonzini     abi_ulong    pr_flag;        /* flags */
4023c227f099SAnthony Liguori     target_uid_t pr_uid;
4024c227f099SAnthony Liguori     target_gid_t pr_gid;
4025c227f099SAnthony Liguori     target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
4026edf8e2afSMika Westerberg     /* Lots missing */
4027d7eb2b92SAlistair Francis     char    pr_fname[16] QEMU_NONSTRING; /* filename of executable */
4028edf8e2afSMika Westerberg     char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
4029edf8e2afSMika Westerberg };
4030edf8e2afSMika Westerberg 
4031edf8e2afSMika Westerberg /* Here is the structure in which status of each thread is captured. */
4032edf8e2afSMika Westerberg struct elf_thread_status {
403372cf2d4fSBlue Swirl     QTAILQ_ENTRY(elf_thread_status)  ets_link;
4034a2547a13SLaurent Desnogues     struct target_elf_prstatus prstatus;   /* NT_PRSTATUS */
4035edf8e2afSMika Westerberg #if 0
4036edf8e2afSMika Westerberg     elf_fpregset_t fpu;             /* NT_PRFPREG */
4037edf8e2afSMika Westerberg     struct task_struct *thread;
4038edf8e2afSMika Westerberg     elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
4039edf8e2afSMika Westerberg #endif
4040edf8e2afSMika Westerberg     struct memelfnote notes[1];
4041edf8e2afSMika Westerberg     int num_notes;
4042edf8e2afSMika Westerberg };
4043edf8e2afSMika Westerberg 
4044edf8e2afSMika Westerberg struct elf_note_info {
4045edf8e2afSMika Westerberg     struct memelfnote   *notes;
4046a2547a13SLaurent Desnogues     struct target_elf_prstatus *prstatus;  /* NT_PRSTATUS */
4047a2547a13SLaurent Desnogues     struct target_elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
4048edf8e2afSMika Westerberg 
4049b58deb34SPaolo Bonzini     QTAILQ_HEAD(, elf_thread_status) thread_list;
4050edf8e2afSMika Westerberg #if 0
4051edf8e2afSMika Westerberg     /*
4052edf8e2afSMika Westerberg      * Current version of ELF coredump doesn't support
4053edf8e2afSMika Westerberg      * dumping fp regs etc.
4054edf8e2afSMika Westerberg      */
4055edf8e2afSMika Westerberg     elf_fpregset_t *fpu;
4056edf8e2afSMika Westerberg     elf_fpxregset_t *xfpu;
4057edf8e2afSMika Westerberg     int thread_status_size;
4058edf8e2afSMika Westerberg #endif
4059edf8e2afSMika Westerberg     int notes_size;
4060edf8e2afSMika Westerberg     int numnote;
4061edf8e2afSMika Westerberg };
4062edf8e2afSMika Westerberg 
4063edf8e2afSMika Westerberg struct vm_area_struct {
40641a1c4db9SMikhail Ilyin     target_ulong   vma_start;  /* start vaddr of memory region */
40651a1c4db9SMikhail Ilyin     target_ulong   vma_end;    /* end vaddr of memory region */
4066edf8e2afSMika Westerberg     abi_ulong      vma_flags;  /* protection etc. flags for the region */
406772cf2d4fSBlue Swirl     QTAILQ_ENTRY(vm_area_struct) vma_link;
4068edf8e2afSMika Westerberg };
4069edf8e2afSMika Westerberg 
4070edf8e2afSMika Westerberg struct mm_struct {
407172cf2d4fSBlue Swirl     QTAILQ_HEAD(, vm_area_struct) mm_mmap;
4072edf8e2afSMika Westerberg     int mm_count;           /* number of mappings */
4073edf8e2afSMika Westerberg };
4074edf8e2afSMika Westerberg 
4075edf8e2afSMika Westerberg static struct mm_struct *vma_init(void);
4076edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *);
40771a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *, target_ulong,
40781a1c4db9SMikhail Ilyin                            target_ulong, abi_ulong);
4079edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *);
4080edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *);
4081edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *);
4082edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *);
40831a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
4084edf8e2afSMika Westerberg                       unsigned long flags);
4085edf8e2afSMika Westerberg 
4086edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
4087edf8e2afSMika Westerberg static void fill_note(struct memelfnote *, const char *, int,
4088edf8e2afSMika Westerberg                       unsigned int, void *);
4089a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
4090a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
4091edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *, const TaskState *);
4092edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
4093edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *);
4094edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *);
40959349b4f9SAndreas Färber static int fill_note_info(struct elf_note_info *, long, const CPUArchState *);
40969349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *, const CPUArchState *);
4097edf8e2afSMika Westerberg 
4098edf8e2afSMika Westerberg static int dump_write(int, const void *, size_t);
4099edf8e2afSMika Westerberg static int write_note(struct memelfnote *, int);
4100edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *, int);
4101edf8e2afSMika Westerberg 
4102edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
4103a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *prstatus)
4104edf8e2afSMika Westerberg {
4105ca98ac83SPaolo Bonzini     prstatus->pr_info.si_signo = tswap32(prstatus->pr_info.si_signo);
4106ca98ac83SPaolo Bonzini     prstatus->pr_info.si_code = tswap32(prstatus->pr_info.si_code);
4107ca98ac83SPaolo Bonzini     prstatus->pr_info.si_errno = tswap32(prstatus->pr_info.si_errno);
4108edf8e2afSMika Westerberg     prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
4109ca98ac83SPaolo Bonzini     prstatus->pr_sigpend = tswapal(prstatus->pr_sigpend);
4110ca98ac83SPaolo Bonzini     prstatus->pr_sighold = tswapal(prstatus->pr_sighold);
4111edf8e2afSMika Westerberg     prstatus->pr_pid = tswap32(prstatus->pr_pid);
4112edf8e2afSMika Westerberg     prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
4113edf8e2afSMika Westerberg     prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
4114edf8e2afSMika Westerberg     prstatus->pr_sid = tswap32(prstatus->pr_sid);
4115edf8e2afSMika Westerberg     /* cpu times are not filled, so we skip them */
4116edf8e2afSMika Westerberg     /* regs should be in correct format already */
4117edf8e2afSMika Westerberg     prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
4118edf8e2afSMika Westerberg }
4119edf8e2afSMika Westerberg 
4120a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
4121edf8e2afSMika Westerberg {
4122ca98ac83SPaolo Bonzini     psinfo->pr_flag = tswapal(psinfo->pr_flag);
4123edf8e2afSMika Westerberg     psinfo->pr_uid = tswap16(psinfo->pr_uid);
4124edf8e2afSMika Westerberg     psinfo->pr_gid = tswap16(psinfo->pr_gid);
4125edf8e2afSMika Westerberg     psinfo->pr_pid = tswap32(psinfo->pr_pid);
4126edf8e2afSMika Westerberg     psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
4127edf8e2afSMika Westerberg     psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
4128edf8e2afSMika Westerberg     psinfo->pr_sid = tswap32(psinfo->pr_sid);
4129edf8e2afSMika Westerberg }
4130991f8f0cSRichard Henderson 
4131991f8f0cSRichard Henderson static void bswap_note(struct elf_note *en)
4132991f8f0cSRichard Henderson {
4133991f8f0cSRichard Henderson     bswap32s(&en->n_namesz);
4134991f8f0cSRichard Henderson     bswap32s(&en->n_descsz);
4135991f8f0cSRichard Henderson     bswap32s(&en->n_type);
4136991f8f0cSRichard Henderson }
4137991f8f0cSRichard Henderson #else
4138991f8f0cSRichard Henderson static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
4139991f8f0cSRichard Henderson static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
4140991f8f0cSRichard Henderson static inline void bswap_note(struct elf_note *en) { }
4141edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
4142edf8e2afSMika Westerberg 
4143edf8e2afSMika Westerberg /*
4144edf8e2afSMika Westerberg  * Minimal support for linux memory regions.  These are needed
4145edf8e2afSMika Westerberg  * when we are finding out what memory exactly belongs to
4146edf8e2afSMika Westerberg  * emulated process.  No locks needed here, as long as
4147edf8e2afSMika Westerberg  * thread that received the signal is stopped.
4148edf8e2afSMika Westerberg  */
4149edf8e2afSMika Westerberg 
4150edf8e2afSMika Westerberg static struct mm_struct *vma_init(void)
4151edf8e2afSMika Westerberg {
4152edf8e2afSMika Westerberg     struct mm_struct *mm;
4153edf8e2afSMika Westerberg 
41547267c094SAnthony Liguori     if ((mm = g_malloc(sizeof (*mm))) == NULL)
4155edf8e2afSMika Westerberg         return (NULL);
4156edf8e2afSMika Westerberg 
4157edf8e2afSMika Westerberg     mm->mm_count = 0;
415872cf2d4fSBlue Swirl     QTAILQ_INIT(&mm->mm_mmap);
4159edf8e2afSMika Westerberg 
4160edf8e2afSMika Westerberg     return (mm);
4161edf8e2afSMika Westerberg }
4162edf8e2afSMika Westerberg 
4163edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *mm)
4164edf8e2afSMika Westerberg {
4165edf8e2afSMika Westerberg     struct vm_area_struct *vma;
4166edf8e2afSMika Westerberg 
4167edf8e2afSMika Westerberg     while ((vma = vma_first(mm)) != NULL) {
416872cf2d4fSBlue Swirl         QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
41697267c094SAnthony Liguori         g_free(vma);
4170edf8e2afSMika Westerberg     }
41717267c094SAnthony Liguori     g_free(mm);
4172edf8e2afSMika Westerberg }
4173edf8e2afSMika Westerberg 
41741a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *mm, target_ulong start,
41751a1c4db9SMikhail Ilyin                            target_ulong end, abi_ulong flags)
4176edf8e2afSMika Westerberg {
4177edf8e2afSMika Westerberg     struct vm_area_struct *vma;
4178edf8e2afSMika Westerberg 
41797267c094SAnthony Liguori     if ((vma = g_malloc0(sizeof (*vma))) == NULL)
4180edf8e2afSMika Westerberg         return (-1);
4181edf8e2afSMika Westerberg 
4182edf8e2afSMika Westerberg     vma->vma_start = start;
4183edf8e2afSMika Westerberg     vma->vma_end = end;
4184edf8e2afSMika Westerberg     vma->vma_flags = flags;
4185edf8e2afSMika Westerberg 
418672cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
4187edf8e2afSMika Westerberg     mm->mm_count++;
4188edf8e2afSMika Westerberg 
4189edf8e2afSMika Westerberg     return (0);
4190edf8e2afSMika Westerberg }
4191edf8e2afSMika Westerberg 
4192edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *mm)
4193edf8e2afSMika Westerberg {
419472cf2d4fSBlue Swirl     return (QTAILQ_FIRST(&mm->mm_mmap));
4195edf8e2afSMika Westerberg }
4196edf8e2afSMika Westerberg 
4197edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
4198edf8e2afSMika Westerberg {
419972cf2d4fSBlue Swirl     return (QTAILQ_NEXT(vma, vma_link));
4200edf8e2afSMika Westerberg }
4201edf8e2afSMika Westerberg 
4202edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *mm)
4203edf8e2afSMika Westerberg {
4204edf8e2afSMika Westerberg     return (mm->mm_count);
4205edf8e2afSMika Westerberg }
4206edf8e2afSMika Westerberg 
4207edf8e2afSMika Westerberg /*
4208edf8e2afSMika Westerberg  * Calculate file (dump) size of given memory region.
4209edf8e2afSMika Westerberg  */
4210edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
4211edf8e2afSMika Westerberg {
4212edf8e2afSMika Westerberg     /* if we cannot even read the first page, skip it */
4213c7169b02SRichard Henderson     if (!access_ok_untagged(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
4214edf8e2afSMika Westerberg         return (0);
4215edf8e2afSMika Westerberg 
4216edf8e2afSMika Westerberg     /*
4217edf8e2afSMika Westerberg      * Usually we don't dump executable pages as they contain
4218edf8e2afSMika Westerberg      * non-writable code that debugger can read directly from
4219edf8e2afSMika Westerberg      * target library etc.  However, thread stacks are marked
4220edf8e2afSMika Westerberg      * also executable so we read in first page of given region
4221edf8e2afSMika Westerberg      * and check whether it contains elf header.  If there is
4222edf8e2afSMika Westerberg      * no elf header, we dump it.
4223edf8e2afSMika Westerberg      */
4224edf8e2afSMika Westerberg     if (vma->vma_flags & PROT_EXEC) {
4225edf8e2afSMika Westerberg         char page[TARGET_PAGE_SIZE];
4226edf8e2afSMika Westerberg 
4227022625a8SPeter Maydell         if (copy_from_user(page, vma->vma_start, sizeof (page))) {
4228022625a8SPeter Maydell             return 0;
4229022625a8SPeter Maydell         }
4230edf8e2afSMika Westerberg         if ((page[EI_MAG0] == ELFMAG0) &&
4231edf8e2afSMika Westerberg             (page[EI_MAG1] == ELFMAG1) &&
4232edf8e2afSMika Westerberg             (page[EI_MAG2] == ELFMAG2) &&
4233edf8e2afSMika Westerberg             (page[EI_MAG3] == ELFMAG3)) {
4234edf8e2afSMika Westerberg             /*
4235edf8e2afSMika Westerberg              * Mappings are possibly from ELF binary.  Don't dump
4236edf8e2afSMika Westerberg              * them.
4237edf8e2afSMika Westerberg              */
4238edf8e2afSMika Westerberg             return (0);
4239edf8e2afSMika Westerberg         }
4240edf8e2afSMika Westerberg     }
4241edf8e2afSMika Westerberg 
4242edf8e2afSMika Westerberg     return (vma->vma_end - vma->vma_start);
4243edf8e2afSMika Westerberg }
4244edf8e2afSMika Westerberg 
42451a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
4246edf8e2afSMika Westerberg                       unsigned long flags)
4247edf8e2afSMika Westerberg {
4248edf8e2afSMika Westerberg     struct mm_struct *mm = (struct mm_struct *)priv;
4249edf8e2afSMika Westerberg 
4250edf8e2afSMika Westerberg     vma_add_mapping(mm, start, end, flags);
4251edf8e2afSMika Westerberg     return (0);
4252edf8e2afSMika Westerberg }
4253edf8e2afSMika Westerberg 
4254edf8e2afSMika Westerberg static void fill_note(struct memelfnote *note, const char *name, int type,
4255edf8e2afSMika Westerberg                       unsigned int sz, void *data)
4256edf8e2afSMika Westerberg {
4257edf8e2afSMika Westerberg     unsigned int namesz;
4258edf8e2afSMika Westerberg 
4259edf8e2afSMika Westerberg     namesz = strlen(name) + 1;
4260edf8e2afSMika Westerberg     note->name = name;
4261edf8e2afSMika Westerberg     note->namesz = namesz;
4262edf8e2afSMika Westerberg     note->namesz_rounded = roundup(namesz, sizeof (int32_t));
4263edf8e2afSMika Westerberg     note->type = type;
426480f5ce75SLaurent Vivier     note->datasz = sz;
426580f5ce75SLaurent Vivier     note->datasz_rounded = roundup(sz, sizeof (int32_t));
426680f5ce75SLaurent Vivier 
4267edf8e2afSMika Westerberg     note->data = data;
4268edf8e2afSMika Westerberg 
4269edf8e2afSMika Westerberg     /*
4270edf8e2afSMika Westerberg      * We calculate rounded up note size here as specified by
4271edf8e2afSMika Westerberg      * ELF document.
4272edf8e2afSMika Westerberg      */
4273edf8e2afSMika Westerberg     note->notesz = sizeof (struct elf_note) +
427480f5ce75SLaurent Vivier         note->namesz_rounded + note->datasz_rounded;
4275edf8e2afSMika Westerberg }
4276edf8e2afSMika Westerberg 
4277edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
4278edf8e2afSMika Westerberg                             uint32_t flags)
4279edf8e2afSMika Westerberg {
4280edf8e2afSMika Westerberg     (void) memset(elf, 0, sizeof(*elf));
4281edf8e2afSMika Westerberg 
4282edf8e2afSMika Westerberg     (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
4283edf8e2afSMika Westerberg     elf->e_ident[EI_CLASS] = ELF_CLASS;
4284edf8e2afSMika Westerberg     elf->e_ident[EI_DATA] = ELF_DATA;
4285edf8e2afSMika Westerberg     elf->e_ident[EI_VERSION] = EV_CURRENT;
4286edf8e2afSMika Westerberg     elf->e_ident[EI_OSABI] = ELF_OSABI;
4287edf8e2afSMika Westerberg 
4288edf8e2afSMika Westerberg     elf->e_type = ET_CORE;
4289edf8e2afSMika Westerberg     elf->e_machine = machine;
4290edf8e2afSMika Westerberg     elf->e_version = EV_CURRENT;
4291edf8e2afSMika Westerberg     elf->e_phoff = sizeof(struct elfhdr);
4292edf8e2afSMika Westerberg     elf->e_flags = flags;
4293edf8e2afSMika Westerberg     elf->e_ehsize = sizeof(struct elfhdr);
4294edf8e2afSMika Westerberg     elf->e_phentsize = sizeof(struct elf_phdr);
4295edf8e2afSMika Westerberg     elf->e_phnum = segs;
4296edf8e2afSMika Westerberg 
4297edf8e2afSMika Westerberg     bswap_ehdr(elf);
4298edf8e2afSMika Westerberg }
4299edf8e2afSMika Westerberg 
4300edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
4301edf8e2afSMika Westerberg {
4302edf8e2afSMika Westerberg     phdr->p_type = PT_NOTE;
4303edf8e2afSMika Westerberg     phdr->p_offset = offset;
4304edf8e2afSMika Westerberg     phdr->p_vaddr = 0;
4305edf8e2afSMika Westerberg     phdr->p_paddr = 0;
4306edf8e2afSMika Westerberg     phdr->p_filesz = sz;
4307edf8e2afSMika Westerberg     phdr->p_memsz = 0;
4308edf8e2afSMika Westerberg     phdr->p_flags = 0;
4309edf8e2afSMika Westerberg     phdr->p_align = 0;
4310edf8e2afSMika Westerberg 
4311991f8f0cSRichard Henderson     bswap_phdr(phdr, 1);
4312edf8e2afSMika Westerberg }
4313edf8e2afSMika Westerberg 
4314edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *note)
4315edf8e2afSMika Westerberg {
4316edf8e2afSMika Westerberg     return (note->notesz);
4317edf8e2afSMika Westerberg }
4318edf8e2afSMika Westerberg 
4319a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *prstatus,
4320edf8e2afSMika Westerberg                           const TaskState *ts, int signr)
4321edf8e2afSMika Westerberg {
4322edf8e2afSMika Westerberg     (void) memset(prstatus, 0, sizeof (*prstatus));
4323edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
4324edf8e2afSMika Westerberg     prstatus->pr_pid = ts->ts_tid;
4325edf8e2afSMika Westerberg     prstatus->pr_ppid = getppid();
4326edf8e2afSMika Westerberg     prstatus->pr_pgrp = getpgrp();
4327edf8e2afSMika Westerberg     prstatus->pr_sid = getsid(0);
4328edf8e2afSMika Westerberg 
4329edf8e2afSMika Westerberg     bswap_prstatus(prstatus);
4330edf8e2afSMika Westerberg }
4331edf8e2afSMika Westerberg 
4332a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
4333edf8e2afSMika Westerberg {
4334900cfbcaSJim Meyering     char *base_filename;
4335edf8e2afSMika Westerberg     unsigned int i, len;
4336edf8e2afSMika Westerberg 
4337edf8e2afSMika Westerberg     (void) memset(psinfo, 0, sizeof (*psinfo));
4338edf8e2afSMika Westerberg 
43395f779a3aSIlya Leoshkevich     len = ts->info->env_strings - ts->info->arg_strings;
4340edf8e2afSMika Westerberg     if (len >= ELF_PRARGSZ)
4341edf8e2afSMika Westerberg         len = ELF_PRARGSZ - 1;
43425f779a3aSIlya Leoshkevich     if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_strings, len)) {
4343edf8e2afSMika Westerberg         return -EFAULT;
43445f779a3aSIlya Leoshkevich     }
4345edf8e2afSMika Westerberg     for (i = 0; i < len; i++)
4346edf8e2afSMika Westerberg         if (psinfo->pr_psargs[i] == 0)
4347edf8e2afSMika Westerberg             psinfo->pr_psargs[i] = ' ';
4348edf8e2afSMika Westerberg     psinfo->pr_psargs[len] = 0;
4349edf8e2afSMika Westerberg 
4350edf8e2afSMika Westerberg     psinfo->pr_pid = getpid();
4351edf8e2afSMika Westerberg     psinfo->pr_ppid = getppid();
4352edf8e2afSMika Westerberg     psinfo->pr_pgrp = getpgrp();
4353edf8e2afSMika Westerberg     psinfo->pr_sid = getsid(0);
4354edf8e2afSMika Westerberg     psinfo->pr_uid = getuid();
4355edf8e2afSMika Westerberg     psinfo->pr_gid = getgid();
4356edf8e2afSMika Westerberg 
4357900cfbcaSJim Meyering     base_filename = g_path_get_basename(ts->bprm->filename);
4358900cfbcaSJim Meyering     /*
4359900cfbcaSJim Meyering      * Using strncpy here is fine: at max-length,
4360900cfbcaSJim Meyering      * this field is not NUL-terminated.
4361900cfbcaSJim Meyering      */
4362edf8e2afSMika Westerberg     (void) strncpy(psinfo->pr_fname, base_filename,
4363edf8e2afSMika Westerberg                    sizeof(psinfo->pr_fname));
4364edf8e2afSMika Westerberg 
4365900cfbcaSJim Meyering     g_free(base_filename);
4366edf8e2afSMika Westerberg     bswap_psinfo(psinfo);
4367edf8e2afSMika Westerberg     return (0);
4368edf8e2afSMika Westerberg }
4369edf8e2afSMika Westerberg 
4370edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
4371edf8e2afSMika Westerberg {
4372edf8e2afSMika Westerberg     elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
4373edf8e2afSMika Westerberg     elf_addr_t orig_auxv = auxv;
4374edf8e2afSMika Westerberg     void *ptr;
4375125b0f55SAlexander Graf     int len = ts->info->auxv_len;
4376edf8e2afSMika Westerberg 
4377edf8e2afSMika Westerberg     /*
4378edf8e2afSMika Westerberg      * Auxiliary vector is stored in target process stack.  It contains
4379edf8e2afSMika Westerberg      * {type, value} pairs that we need to dump into note.  This is not
4380edf8e2afSMika Westerberg      * strictly necessary but we do it here for sake of completeness.
4381edf8e2afSMika Westerberg      */
4382edf8e2afSMika Westerberg 
4383edf8e2afSMika Westerberg     /* read in whole auxv vector and copy it to memelfnote */
4384edf8e2afSMika Westerberg     ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
4385edf8e2afSMika Westerberg     if (ptr != NULL) {
4386edf8e2afSMika Westerberg         fill_note(note, "CORE", NT_AUXV, len, ptr);
4387edf8e2afSMika Westerberg         unlock_user(ptr, auxv, len);
4388edf8e2afSMika Westerberg     }
4389edf8e2afSMika Westerberg }
4390edf8e2afSMika Westerberg 
4391edf8e2afSMika Westerberg /*
4392edf8e2afSMika Westerberg  * Constructs name of coredump file.  We have following convention
4393edf8e2afSMika Westerberg  * for the name:
4394edf8e2afSMika Westerberg  *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
4395edf8e2afSMika Westerberg  *
439668af19adSDaniel P. Berrangé  * Returns the filename
4397edf8e2afSMika Westerberg  */
439868af19adSDaniel P. Berrangé static char *core_dump_filename(const TaskState *ts)
4399edf8e2afSMika Westerberg {
440068af19adSDaniel P. Berrangé     g_autoptr(GDateTime) now = g_date_time_new_now_local();
440168af19adSDaniel P. Berrangé     g_autofree char *nowstr = g_date_time_format(now, "%Y%m%d-%H%M%S");
440268af19adSDaniel P. Berrangé     g_autofree char *base_filename = g_path_get_basename(ts->bprm->filename);
4403edf8e2afSMika Westerberg 
440468af19adSDaniel P. Berrangé     return g_strdup_printf("qemu_%s_%s_%d.core",
440568af19adSDaniel P. Berrangé                            base_filename, nowstr, (int)getpid());
4406edf8e2afSMika Westerberg }
4407edf8e2afSMika Westerberg 
4408edf8e2afSMika Westerberg static int dump_write(int fd, const void *ptr, size_t size)
4409edf8e2afSMika Westerberg {
4410edf8e2afSMika Westerberg     const char *bufp = (const char *)ptr;
4411edf8e2afSMika Westerberg     ssize_t bytes_written, bytes_left;
4412edf8e2afSMika Westerberg     struct rlimit dumpsize;
4413edf8e2afSMika Westerberg     off_t pos;
4414edf8e2afSMika Westerberg 
4415edf8e2afSMika Westerberg     bytes_written = 0;
4416edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
4417edf8e2afSMika Westerberg     if ((pos = lseek(fd, 0, SEEK_CUR))==-1) {
4418edf8e2afSMika Westerberg         if (errno == ESPIPE) { /* not a seekable stream */
4419edf8e2afSMika Westerberg             bytes_left = size;
4420edf8e2afSMika Westerberg         } else {
4421edf8e2afSMika Westerberg             return pos;
4422edf8e2afSMika Westerberg         }
4423edf8e2afSMika Westerberg     } else {
4424edf8e2afSMika Westerberg         if (dumpsize.rlim_cur <= pos) {
4425edf8e2afSMika Westerberg             return -1;
4426edf8e2afSMika Westerberg         } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
4427edf8e2afSMika Westerberg             bytes_left = size;
4428edf8e2afSMika Westerberg         } else {
4429edf8e2afSMika Westerberg             size_t limit_left=dumpsize.rlim_cur - pos;
4430edf8e2afSMika Westerberg             bytes_left = limit_left >= size ? size : limit_left ;
4431edf8e2afSMika Westerberg         }
4432edf8e2afSMika Westerberg     }
4433edf8e2afSMika Westerberg 
4434edf8e2afSMika Westerberg     /*
4435edf8e2afSMika Westerberg      * In normal conditions, single write(2) should do but
4436edf8e2afSMika Westerberg      * in case of socket etc. this mechanism is more portable.
4437edf8e2afSMika Westerberg      */
4438edf8e2afSMika Westerberg     do {
4439edf8e2afSMika Westerberg         bytes_written = write(fd, bufp, bytes_left);
4440edf8e2afSMika Westerberg         if (bytes_written < 0) {
4441edf8e2afSMika Westerberg             if (errno == EINTR)
4442edf8e2afSMika Westerberg                 continue;
4443edf8e2afSMika Westerberg             return (-1);
4444edf8e2afSMika Westerberg         } else if (bytes_written == 0) { /* eof */
4445edf8e2afSMika Westerberg             return (-1);
4446edf8e2afSMika Westerberg         }
4447edf8e2afSMika Westerberg         bufp += bytes_written;
4448edf8e2afSMika Westerberg         bytes_left -= bytes_written;
4449edf8e2afSMika Westerberg     } while (bytes_left > 0);
4450edf8e2afSMika Westerberg 
4451edf8e2afSMika Westerberg     return (0);
4452edf8e2afSMika Westerberg }
4453edf8e2afSMika Westerberg 
4454edf8e2afSMika Westerberg static int write_note(struct memelfnote *men, int fd)
4455edf8e2afSMika Westerberg {
4456edf8e2afSMika Westerberg     struct elf_note en;
4457edf8e2afSMika Westerberg 
4458edf8e2afSMika Westerberg     en.n_namesz = men->namesz;
4459edf8e2afSMika Westerberg     en.n_type = men->type;
4460edf8e2afSMika Westerberg     en.n_descsz = men->datasz;
4461edf8e2afSMika Westerberg 
4462edf8e2afSMika Westerberg     bswap_note(&en);
4463edf8e2afSMika Westerberg 
4464edf8e2afSMika Westerberg     if (dump_write(fd, &en, sizeof(en)) != 0)
4465edf8e2afSMika Westerberg         return (-1);
4466edf8e2afSMika Westerberg     if (dump_write(fd, men->name, men->namesz_rounded) != 0)
4467edf8e2afSMika Westerberg         return (-1);
446880f5ce75SLaurent Vivier     if (dump_write(fd, men->data, men->datasz_rounded) != 0)
4469edf8e2afSMika Westerberg         return (-1);
4470edf8e2afSMika Westerberg 
4471edf8e2afSMika Westerberg     return (0);
4472edf8e2afSMika Westerberg }
4473edf8e2afSMika Westerberg 
44749349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *info, const CPUArchState *env)
4475edf8e2afSMika Westerberg {
447629a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
44770429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4478edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4479edf8e2afSMika Westerberg 
44807267c094SAnthony Liguori     ets = g_malloc0(sizeof (*ets));
4481edf8e2afSMika Westerberg     ets->num_notes = 1; /* only prstatus is dumped */
4482edf8e2afSMika Westerberg     fill_prstatus(&ets->prstatus, ts, 0);
4483edf8e2afSMika Westerberg     elf_core_copy_regs(&ets->prstatus.pr_reg, env);
4484edf8e2afSMika Westerberg     fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
4485edf8e2afSMika Westerberg               &ets->prstatus);
4486edf8e2afSMika Westerberg 
448772cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
4488edf8e2afSMika Westerberg 
4489edf8e2afSMika Westerberg     info->notes_size += note_size(&ets->notes[0]);
4490edf8e2afSMika Westerberg }
4491edf8e2afSMika Westerberg 
44926afafa86SPeter Maydell static void init_note_info(struct elf_note_info *info)
44936afafa86SPeter Maydell {
44946afafa86SPeter Maydell     /* Initialize the elf_note_info structure so that it is at
44956afafa86SPeter Maydell      * least safe to call free_note_info() on it. Must be
44966afafa86SPeter Maydell      * called before calling fill_note_info().
44976afafa86SPeter Maydell      */
44986afafa86SPeter Maydell     memset(info, 0, sizeof (*info));
44996afafa86SPeter Maydell     QTAILQ_INIT(&info->thread_list);
45006afafa86SPeter Maydell }
45016afafa86SPeter Maydell 
4502edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *info,
45039349b4f9SAndreas Färber                           long signr, const CPUArchState *env)
4504edf8e2afSMika Westerberg {
4505edf8e2afSMika Westerberg #define NUMNOTES 3
450629a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
45070429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4508edf8e2afSMika Westerberg     int i;
4509edf8e2afSMika Westerberg 
4510c78d65e8SMarkus Armbruster     info->notes = g_new0(struct memelfnote, NUMNOTES);
4511edf8e2afSMika Westerberg     if (info->notes == NULL)
4512edf8e2afSMika Westerberg         return (-ENOMEM);
45137267c094SAnthony Liguori     info->prstatus = g_malloc0(sizeof (*info->prstatus));
4514edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4515edf8e2afSMika Westerberg         return (-ENOMEM);
45167267c094SAnthony Liguori     info->psinfo = g_malloc0(sizeof (*info->psinfo));
4517edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4518edf8e2afSMika Westerberg         return (-ENOMEM);
4519edf8e2afSMika Westerberg 
4520edf8e2afSMika Westerberg     /*
4521edf8e2afSMika Westerberg      * First fill in status (and registers) of current thread
4522edf8e2afSMika Westerberg      * including process info & aux vector.
4523edf8e2afSMika Westerberg      */
4524edf8e2afSMika Westerberg     fill_prstatus(info->prstatus, ts, signr);
4525edf8e2afSMika Westerberg     elf_core_copy_regs(&info->prstatus->pr_reg, env);
4526edf8e2afSMika Westerberg     fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
4527edf8e2afSMika Westerberg               sizeof (*info->prstatus), info->prstatus);
4528edf8e2afSMika Westerberg     fill_psinfo(info->psinfo, ts);
4529edf8e2afSMika Westerberg     fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
4530edf8e2afSMika Westerberg               sizeof (*info->psinfo), info->psinfo);
4531edf8e2afSMika Westerberg     fill_auxv_note(&info->notes[2], ts);
4532edf8e2afSMika Westerberg     info->numnote = 3;
4533edf8e2afSMika Westerberg 
4534edf8e2afSMika Westerberg     info->notes_size = 0;
4535edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4536edf8e2afSMika Westerberg         info->notes_size += note_size(&info->notes[i]);
4537edf8e2afSMika Westerberg 
4538edf8e2afSMika Westerberg     /* read and fill status of all threads */
4539370ed600SJamie Iles     WITH_QEMU_LOCK_GUARD(&qemu_cpu_list_lock) {
4540bdc44640SAndreas Färber         CPU_FOREACH(cpu) {
4541a2247f8eSAndreas Färber             if (cpu == thread_cpu) {
4542edf8e2afSMika Westerberg                 continue;
4543182735efSAndreas Färber             }
4544b77af26eSRichard Henderson             fill_thread_info(info, cpu_env(cpu));
4545edf8e2afSMika Westerberg         }
4546370ed600SJamie Iles     }
4547edf8e2afSMika Westerberg 
4548edf8e2afSMika Westerberg     return (0);
4549edf8e2afSMika Westerberg }
4550edf8e2afSMika Westerberg 
4551edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *info)
4552edf8e2afSMika Westerberg {
4553edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4554edf8e2afSMika Westerberg 
455572cf2d4fSBlue Swirl     while (!QTAILQ_EMPTY(&info->thread_list)) {
455672cf2d4fSBlue Swirl         ets = QTAILQ_FIRST(&info->thread_list);
455772cf2d4fSBlue Swirl         QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
45587267c094SAnthony Liguori         g_free(ets);
4559edf8e2afSMika Westerberg     }
4560edf8e2afSMika Westerberg 
45617267c094SAnthony Liguori     g_free(info->prstatus);
45627267c094SAnthony Liguori     g_free(info->psinfo);
45637267c094SAnthony Liguori     g_free(info->notes);
4564edf8e2afSMika Westerberg }
4565edf8e2afSMika Westerberg 
4566edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *info, int fd)
4567edf8e2afSMika Westerberg {
4568edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4569edf8e2afSMika Westerberg     int i, error = 0;
4570edf8e2afSMika Westerberg 
4571edf8e2afSMika Westerberg     /* write prstatus, psinfo and auxv for current thread */
4572edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4573edf8e2afSMika Westerberg         if ((error = write_note(&info->notes[i], fd)) != 0)
4574edf8e2afSMika Westerberg             return (error);
4575edf8e2afSMika Westerberg 
4576edf8e2afSMika Westerberg     /* write prstatus for each thread */
457752a53afeSEmilio G. Cota     QTAILQ_FOREACH(ets, &info->thread_list, ets_link) {
4578edf8e2afSMika Westerberg         if ((error = write_note(&ets->notes[0], fd)) != 0)
4579edf8e2afSMika Westerberg             return (error);
4580edf8e2afSMika Westerberg     }
4581edf8e2afSMika Westerberg 
4582edf8e2afSMika Westerberg     return (0);
4583edf8e2afSMika Westerberg }
4584edf8e2afSMika Westerberg 
4585edf8e2afSMika Westerberg /*
4586edf8e2afSMika Westerberg  * Write out ELF coredump.
4587edf8e2afSMika Westerberg  *
4588edf8e2afSMika Westerberg  * See documentation of ELF object file format in:
4589edf8e2afSMika Westerberg  * http://www.caldera.com/developers/devspecs/gabi41.pdf
4590edf8e2afSMika Westerberg  *
4591edf8e2afSMika Westerberg  * Coredump format in linux is following:
4592edf8e2afSMika Westerberg  *
4593edf8e2afSMika Westerberg  * 0   +----------------------+         \
4594edf8e2afSMika Westerberg  *     | ELF header           | ET_CORE  |
4595edf8e2afSMika Westerberg  *     +----------------------+          |
4596edf8e2afSMika Westerberg  *     | ELF program headers  |          |--- headers
4597edf8e2afSMika Westerberg  *     | - NOTE section       |          |
4598edf8e2afSMika Westerberg  *     | - PT_LOAD sections   |          |
4599edf8e2afSMika Westerberg  *     +----------------------+         /
4600edf8e2afSMika Westerberg  *     | NOTEs:               |
4601edf8e2afSMika Westerberg  *     | - NT_PRSTATUS        |
4602edf8e2afSMika Westerberg  *     | - NT_PRSINFO         |
4603edf8e2afSMika Westerberg  *     | - NT_AUXV            |
4604edf8e2afSMika Westerberg  *     +----------------------+ <-- aligned to target page
4605edf8e2afSMika Westerberg  *     | Process memory dump  |
4606edf8e2afSMika Westerberg  *     :                      :
4607edf8e2afSMika Westerberg  *     .                      .
4608edf8e2afSMika Westerberg  *     :                      :
4609edf8e2afSMika Westerberg  *     |                      |
4610edf8e2afSMika Westerberg  *     +----------------------+
4611edf8e2afSMika Westerberg  *
4612edf8e2afSMika Westerberg  * NT_PRSTATUS -> struct elf_prstatus (per thread)
4613edf8e2afSMika Westerberg  * NT_PRSINFO  -> struct elf_prpsinfo
4614edf8e2afSMika Westerberg  * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
4615edf8e2afSMika Westerberg  *
4616edf8e2afSMika Westerberg  * Format follows System V format as close as possible.  Current
4617edf8e2afSMika Westerberg  * version limitations are as follows:
4618edf8e2afSMika Westerberg  *     - no floating point registers are dumped
4619edf8e2afSMika Westerberg  *
4620edf8e2afSMika Westerberg  * Function returns 0 in case of success, negative errno otherwise.
4621edf8e2afSMika Westerberg  *
4622edf8e2afSMika Westerberg  * TODO: make this work also during runtime: it should be
4623edf8e2afSMika Westerberg  * possible to force coredump from running process and then
4624edf8e2afSMika Westerberg  * continue processing.  For example qemu could set up SIGUSR2
4625edf8e2afSMika Westerberg  * handler (provided that target process haven't registered
4626edf8e2afSMika Westerberg  * handler for that) that does the dump when signal is received.
4627edf8e2afSMika Westerberg  */
46289349b4f9SAndreas Färber static int elf_core_dump(int signr, const CPUArchState *env)
4629edf8e2afSMika Westerberg {
463029a0af61SRichard Henderson     const CPUState *cpu = env_cpu((CPUArchState *)env);
46310429a971SAndreas Färber     const TaskState *ts = (const TaskState *)cpu->opaque;
4632edf8e2afSMika Westerberg     struct vm_area_struct *vma = NULL;
463368af19adSDaniel P. Berrangé     g_autofree char *corefile = NULL;
4634edf8e2afSMika Westerberg     struct elf_note_info info;
4635edf8e2afSMika Westerberg     struct elfhdr elf;
4636edf8e2afSMika Westerberg     struct elf_phdr phdr;
4637edf8e2afSMika Westerberg     struct rlimit dumpsize;
4638edf8e2afSMika Westerberg     struct mm_struct *mm = NULL;
4639edf8e2afSMika Westerberg     off_t offset = 0, data_offset = 0;
4640edf8e2afSMika Westerberg     int segs = 0;
4641edf8e2afSMika Westerberg     int fd = -1;
4642edf8e2afSMika Westerberg 
46436afafa86SPeter Maydell     init_note_info(&info);
46446afafa86SPeter Maydell 
4645edf8e2afSMika Westerberg     errno = 0;
4646edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
4647edf8e2afSMika Westerberg     if (dumpsize.rlim_cur == 0)
4648edf8e2afSMika Westerberg         return 0;
4649edf8e2afSMika Westerberg 
465068af19adSDaniel P. Berrangé     corefile = core_dump_filename(ts);
4651edf8e2afSMika Westerberg 
4652edf8e2afSMika Westerberg     if ((fd = open(corefile, O_WRONLY | O_CREAT,
4653edf8e2afSMika Westerberg                    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
4654edf8e2afSMika Westerberg         return (-errno);
4655edf8e2afSMika Westerberg 
4656edf8e2afSMika Westerberg     /*
4657edf8e2afSMika Westerberg      * Walk through target process memory mappings and
4658edf8e2afSMika Westerberg      * set up structure containing this information.  After
4659edf8e2afSMika Westerberg      * this point vma_xxx functions can be used.
4660edf8e2afSMika Westerberg      */
4661edf8e2afSMika Westerberg     if ((mm = vma_init()) == NULL)
4662edf8e2afSMika Westerberg         goto out;
4663edf8e2afSMika Westerberg 
4664edf8e2afSMika Westerberg     walk_memory_regions(mm, vma_walker);
4665edf8e2afSMika Westerberg     segs = vma_get_mapping_count(mm);
4666edf8e2afSMika Westerberg 
4667edf8e2afSMika Westerberg     /*
4668edf8e2afSMika Westerberg      * Construct valid coredump ELF header.  We also
4669edf8e2afSMika Westerberg      * add one more segment for notes.
4670edf8e2afSMika Westerberg      */
4671edf8e2afSMika Westerberg     fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
4672edf8e2afSMika Westerberg     if (dump_write(fd, &elf, sizeof (elf)) != 0)
4673edf8e2afSMika Westerberg         goto out;
4674edf8e2afSMika Westerberg 
4675b6af0975SDaniel P. Berrange     /* fill in the in-memory version of notes */
4676edf8e2afSMika Westerberg     if (fill_note_info(&info, signr, env) < 0)
4677edf8e2afSMika Westerberg         goto out;
4678edf8e2afSMika Westerberg 
4679edf8e2afSMika Westerberg     offset += sizeof (elf);                             /* elf header */
4680edf8e2afSMika Westerberg     offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
4681edf8e2afSMika Westerberg 
4682edf8e2afSMika Westerberg     /* write out notes program header */
4683edf8e2afSMika Westerberg     fill_elf_note_phdr(&phdr, info.notes_size, offset);
4684edf8e2afSMika Westerberg 
4685edf8e2afSMika Westerberg     offset += info.notes_size;
4686edf8e2afSMika Westerberg     if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
4687edf8e2afSMika Westerberg         goto out;
4688edf8e2afSMika Westerberg 
4689edf8e2afSMika Westerberg     /*
4690edf8e2afSMika Westerberg      * ELF specification wants data to start at page boundary so
4691edf8e2afSMika Westerberg      * we align it here.
4692edf8e2afSMika Westerberg      */
469380f5ce75SLaurent Vivier     data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
4694edf8e2afSMika Westerberg 
4695edf8e2afSMika Westerberg     /*
4696edf8e2afSMika Westerberg      * Write program headers for memory regions mapped in
4697edf8e2afSMika Westerberg      * the target process.
4698edf8e2afSMika Westerberg      */
4699edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4700edf8e2afSMika Westerberg         (void) memset(&phdr, 0, sizeof (phdr));
4701edf8e2afSMika Westerberg 
4702edf8e2afSMika Westerberg         phdr.p_type = PT_LOAD;
4703edf8e2afSMika Westerberg         phdr.p_offset = offset;
4704edf8e2afSMika Westerberg         phdr.p_vaddr = vma->vma_start;
4705edf8e2afSMika Westerberg         phdr.p_paddr = 0;
4706edf8e2afSMika Westerberg         phdr.p_filesz = vma_dump_size(vma);
4707edf8e2afSMika Westerberg         offset += phdr.p_filesz;
4708edf8e2afSMika Westerberg         phdr.p_memsz = vma->vma_end - vma->vma_start;
4709edf8e2afSMika Westerberg         phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
4710edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_WRITE)
4711edf8e2afSMika Westerberg             phdr.p_flags |= PF_W;
4712edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_EXEC)
4713edf8e2afSMika Westerberg             phdr.p_flags |= PF_X;
4714edf8e2afSMika Westerberg         phdr.p_align = ELF_EXEC_PAGESIZE;
4715edf8e2afSMika Westerberg 
471680f5ce75SLaurent Vivier         bswap_phdr(&phdr, 1);
4717772034b6SPeter Maydell         if (dump_write(fd, &phdr, sizeof(phdr)) != 0) {
4718772034b6SPeter Maydell             goto out;
4719772034b6SPeter Maydell         }
4720edf8e2afSMika Westerberg     }
4721edf8e2afSMika Westerberg 
4722edf8e2afSMika Westerberg     /*
4723edf8e2afSMika Westerberg      * Next we write notes just after program headers.  No
4724edf8e2afSMika Westerberg      * alignment needed here.
4725edf8e2afSMika Westerberg      */
4726edf8e2afSMika Westerberg     if (write_note_info(&info, fd) < 0)
4727edf8e2afSMika Westerberg         goto out;
4728edf8e2afSMika Westerberg 
4729edf8e2afSMika Westerberg     /* align data to page boundary */
4730edf8e2afSMika Westerberg     if (lseek(fd, data_offset, SEEK_SET) != data_offset)
4731edf8e2afSMika Westerberg         goto out;
4732edf8e2afSMika Westerberg 
4733edf8e2afSMika Westerberg     /*
4734edf8e2afSMika Westerberg      * Finally we can dump process memory into corefile as well.
4735edf8e2afSMika Westerberg      */
4736edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4737edf8e2afSMika Westerberg         abi_ulong addr;
4738edf8e2afSMika Westerberg         abi_ulong end;
4739edf8e2afSMika Westerberg 
4740edf8e2afSMika Westerberg         end = vma->vma_start + vma_dump_size(vma);
4741edf8e2afSMika Westerberg 
4742edf8e2afSMika Westerberg         for (addr = vma->vma_start; addr < end;
4743edf8e2afSMika Westerberg              addr += TARGET_PAGE_SIZE) {
4744edf8e2afSMika Westerberg             char page[TARGET_PAGE_SIZE];
4745edf8e2afSMika Westerberg             int error;
4746edf8e2afSMika Westerberg 
4747edf8e2afSMika Westerberg             /*
4748edf8e2afSMika Westerberg              *  Read in page from target process memory and
4749edf8e2afSMika Westerberg              *  write it to coredump file.
4750edf8e2afSMika Westerberg              */
4751edf8e2afSMika Westerberg             error = copy_from_user(page, addr, sizeof (page));
4752edf8e2afSMika Westerberg             if (error != 0) {
475349995e17SAurelien Jarno                 (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
4754edf8e2afSMika Westerberg                                addr);
4755edf8e2afSMika Westerberg                 errno = -error;
4756edf8e2afSMika Westerberg                 goto out;
4757edf8e2afSMika Westerberg             }
4758edf8e2afSMika Westerberg             if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
4759edf8e2afSMika Westerberg                 goto out;
4760edf8e2afSMika Westerberg         }
4761edf8e2afSMika Westerberg     }
4762edf8e2afSMika Westerberg 
4763edf8e2afSMika Westerberg  out:
4764edf8e2afSMika Westerberg     free_note_info(&info);
4765edf8e2afSMika Westerberg     if (mm != NULL)
4766edf8e2afSMika Westerberg         vma_delete(mm);
4767edf8e2afSMika Westerberg     (void) close(fd);
4768edf8e2afSMika Westerberg 
4769edf8e2afSMika Westerberg     if (errno != 0)
4770edf8e2afSMika Westerberg         return (-errno);
4771edf8e2afSMika Westerberg     return (0);
4772edf8e2afSMika Westerberg }
4773edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
4774edf8e2afSMika Westerberg 
4775e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
4776e5fe0c52Spbrook {
4777e5fe0c52Spbrook     init_thread(regs, infop);
4778e5fe0c52Spbrook }
4779