xref: /qemu/linux-user/elfload.c (revision 3bd0238638070274b9ce3464f0456cdf6ca0884d)
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 
36edf8e2afSMika Westerberg #define ELF_OSABI   ELFOSABI_SYSV
37edf8e2afSMika Westerberg 
38cb33da57Sblueswir1 /* from personality.h */
39cb33da57Sblueswir1 
40cb33da57Sblueswir1 /*
41cb33da57Sblueswir1  * Flags for bug emulation.
42cb33da57Sblueswir1  *
43cb33da57Sblueswir1  * These occupy the top three bytes.
44cb33da57Sblueswir1  */
45cb33da57Sblueswir1 enum {
46cb33da57Sblueswir1     ADDR_NO_RANDOMIZE = 0x0040000,      /* disable randomization of VA space */
47d97ef72eSRichard Henderson     FDPIC_FUNCPTRS =    0x0080000,      /* userspace function ptrs point to
48d97ef72eSRichard Henderson                                            descriptors (signal handling) */
49cb33da57Sblueswir1     MMAP_PAGE_ZERO =    0x0100000,
50cb33da57Sblueswir1     ADDR_COMPAT_LAYOUT = 0x0200000,
51cb33da57Sblueswir1     READ_IMPLIES_EXEC = 0x0400000,
52cb33da57Sblueswir1     ADDR_LIMIT_32BIT =  0x0800000,
53cb33da57Sblueswir1     SHORT_INODE =       0x1000000,
54cb33da57Sblueswir1     WHOLE_SECONDS =     0x2000000,
55cb33da57Sblueswir1     STICKY_TIMEOUTS =   0x4000000,
56cb33da57Sblueswir1     ADDR_LIMIT_3GB =    0x8000000,
57cb33da57Sblueswir1 };
58cb33da57Sblueswir1 
59cb33da57Sblueswir1 /*
60cb33da57Sblueswir1  * Personality types.
61cb33da57Sblueswir1  *
62cb33da57Sblueswir1  * These go in the low byte.  Avoid using the top bit, it will
63cb33da57Sblueswir1  * conflict with error returns.
64cb33da57Sblueswir1  */
65cb33da57Sblueswir1 enum {
66cb33da57Sblueswir1     PER_LINUX =         0x0000,
67cb33da57Sblueswir1     PER_LINUX_32BIT =   0x0000 | ADDR_LIMIT_32BIT,
68cb33da57Sblueswir1     PER_LINUX_FDPIC =   0x0000 | FDPIC_FUNCPTRS,
69cb33da57Sblueswir1     PER_SVR4 =          0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
70cb33da57Sblueswir1     PER_SVR3 =          0x0002 | STICKY_TIMEOUTS | SHORT_INODE,
71d97ef72eSRichard Henderson     PER_SCOSVR3 =       0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE,
72cb33da57Sblueswir1     PER_OSR5 =          0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,
73cb33da57Sblueswir1     PER_WYSEV386 =      0x0004 | STICKY_TIMEOUTS | SHORT_INODE,
74cb33da57Sblueswir1     PER_ISCR4 =         0x0005 | STICKY_TIMEOUTS,
75cb33da57Sblueswir1     PER_BSD =           0x0006,
76cb33da57Sblueswir1     PER_SUNOS =         0x0006 | STICKY_TIMEOUTS,
77cb33da57Sblueswir1     PER_XENIX =         0x0007 | STICKY_TIMEOUTS | SHORT_INODE,
78cb33da57Sblueswir1     PER_LINUX32 =       0x0008,
79cb33da57Sblueswir1     PER_LINUX32_3GB =   0x0008 | ADDR_LIMIT_3GB,
80cb33da57Sblueswir1     PER_IRIX32 =        0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */
81cb33da57Sblueswir1     PER_IRIXN32 =       0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */
82cb33da57Sblueswir1     PER_IRIX64 =        0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */
83cb33da57Sblueswir1     PER_RISCOS =        0x000c,
84cb33da57Sblueswir1     PER_SOLARIS =       0x000d | STICKY_TIMEOUTS,
85cb33da57Sblueswir1     PER_UW7 =           0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
86cb33da57Sblueswir1     PER_OSF4 =          0x000f,                  /* OSF/1 v4 */
87cb33da57Sblueswir1     PER_HPUX =          0x0010,
88cb33da57Sblueswir1     PER_MASK =          0x00ff,
89cb33da57Sblueswir1 };
90cb33da57Sblueswir1 
91cb33da57Sblueswir1 /*
92cb33da57Sblueswir1  * Return the base personality without flags.
93cb33da57Sblueswir1  */
94cb33da57Sblueswir1 #define personality(pers)       (pers & PER_MASK)
95cb33da57Sblueswir1 
963cb10cfaSChristophe Lyon int info_is_fdpic(struct image_info *info)
973cb10cfaSChristophe Lyon {
983cb10cfaSChristophe Lyon     return info->personality == PER_LINUX_FDPIC;
993cb10cfaSChristophe Lyon }
1003cb10cfaSChristophe Lyon 
10183fb7adfSbellard /* this flag is uneffective under linux too, should be deleted */
10283fb7adfSbellard #ifndef MAP_DENYWRITE
10383fb7adfSbellard #define MAP_DENYWRITE 0
10483fb7adfSbellard #endif
10583fb7adfSbellard 
10683fb7adfSbellard /* should probably go in elf.h */
10783fb7adfSbellard #ifndef ELIBBAD
10883fb7adfSbellard #define ELIBBAD 80
10983fb7adfSbellard #endif
11083fb7adfSbellard 
111ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
11228490231SRichard Henderson #define ELF_DATA        ELFDATA2MSB
11328490231SRichard Henderson #else
11428490231SRichard Henderson #define ELF_DATA        ELFDATA2LSB
11528490231SRichard Henderson #endif
11628490231SRichard Henderson 
117a29f998dSPaolo Bonzini #ifdef TARGET_ABI_MIPSN32
118918fc54cSPaolo Bonzini typedef abi_ullong      target_elf_greg_t;
119918fc54cSPaolo Bonzini #define tswapreg(ptr)   tswap64(ptr)
120a29f998dSPaolo Bonzini #else
121a29f998dSPaolo Bonzini typedef abi_ulong       target_elf_greg_t;
122a29f998dSPaolo Bonzini #define tswapreg(ptr)   tswapal(ptr)
123a29f998dSPaolo Bonzini #endif
124a29f998dSPaolo Bonzini 
12521e807faSNathan Froyd #ifdef USE_UID16
1261ddd592fSPaolo Bonzini typedef abi_ushort      target_uid_t;
1271ddd592fSPaolo Bonzini typedef abi_ushort      target_gid_t;
12821e807faSNathan Froyd #else
129f8fd4fc4SPaolo Bonzini typedef abi_uint        target_uid_t;
130f8fd4fc4SPaolo Bonzini typedef abi_uint        target_gid_t;
13121e807faSNathan Froyd #endif
132f8fd4fc4SPaolo Bonzini typedef abi_int         target_pid_t;
13321e807faSNathan Froyd 
13430ac07d4Sbellard #ifdef TARGET_I386
13530ac07d4Sbellard 
13615338fd7Sbellard #define ELF_HWCAP get_elf_hwcap()
13715338fd7Sbellard 
13815338fd7Sbellard static uint32_t get_elf_hwcap(void)
13915338fd7Sbellard {
140a2247f8eSAndreas Färber     X86CPU *cpu = X86_CPU(thread_cpu);
141a2247f8eSAndreas Färber 
142a2247f8eSAndreas Färber     return cpu->env.features[FEAT_1_EDX];
14315338fd7Sbellard }
14415338fd7Sbellard 
14584409ddbSj_mayer #ifdef TARGET_X86_64
14684409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
14784409ddbSj_mayer #define ELF_ARCH       EM_X86_64
14884409ddbSj_mayer 
1499263ba84SRichard Henderson #define ELF_PLATFORM   "x86_64"
1509263ba84SRichard Henderson 
15184409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
15284409ddbSj_mayer {
15384409ddbSj_mayer     regs->rax = 0;
15484409ddbSj_mayer     regs->rsp = infop->start_stack;
15584409ddbSj_mayer     regs->rip = infop->entry;
15684409ddbSj_mayer }
15784409ddbSj_mayer 
1589edc5d79SMika Westerberg #define ELF_NREG    27
159c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
1609edc5d79SMika Westerberg 
1619edc5d79SMika Westerberg /*
1629edc5d79SMika Westerberg  * Note that ELF_NREG should be 29 as there should be place for
1639edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
1649edc5d79SMika Westerberg  * those.
1659edc5d79SMika Westerberg  *
1669edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
1679edc5d79SMika Westerberg  */
16805390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
1699edc5d79SMika Westerberg {
170030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[15]);
171030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[14]);
172030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[13]);
173030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[12]);
174030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EBP]);
175030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBX]);
176030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[11]);
177030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->regs[10]);
178030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->regs[9]);
179030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->regs[8]);
180030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->regs[R_EAX]);
181030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_ECX]);
182030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->regs[R_EDX]);
183030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->regs[R_ESI]);
184030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->regs[R_EDI]);
185030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_EAX]); /* XXX */
186030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->eip);
187030912e0SIlya Leoshkevich     (*regs)[17] = tswapreg(env->segs[R_CS].selector & 0xffff);
188030912e0SIlya Leoshkevich     (*regs)[18] = tswapreg(env->eflags);
189030912e0SIlya Leoshkevich     (*regs)[19] = tswapreg(env->regs[R_ESP]);
190030912e0SIlya Leoshkevich     (*regs)[20] = tswapreg(env->segs[R_SS].selector & 0xffff);
191030912e0SIlya Leoshkevich     (*regs)[21] = tswapreg(env->segs[R_FS].selector & 0xffff);
192030912e0SIlya Leoshkevich     (*regs)[22] = tswapreg(env->segs[R_GS].selector & 0xffff);
193030912e0SIlya Leoshkevich     (*regs)[23] = tswapreg(env->segs[R_DS].selector & 0xffff);
194030912e0SIlya Leoshkevich     (*regs)[24] = tswapreg(env->segs[R_ES].selector & 0xffff);
195030912e0SIlya Leoshkevich     (*regs)[25] = tswapreg(env->segs[R_FS].selector & 0xffff);
196030912e0SIlya Leoshkevich     (*regs)[26] = tswapreg(env->segs[R_GS].selector & 0xffff);
1979edc5d79SMika Westerberg }
1989edc5d79SMika Westerberg 
199d461b73eSRichard Henderson #if ULONG_MAX > UINT32_MAX
200d461b73eSRichard Henderson #define INIT_GUEST_COMMPAGE
201d461b73eSRichard Henderson static bool init_guest_commpage(void)
202d461b73eSRichard Henderson {
203d461b73eSRichard Henderson     /*
204d461b73eSRichard Henderson      * The vsyscall page is at a high negative address aka kernel space,
205d461b73eSRichard Henderson      * which means that we cannot actually allocate it with target_mmap.
206d461b73eSRichard Henderson      * We still should be able to use page_set_flags, unless the user
207d461b73eSRichard Henderson      * has specified -R reserved_va, which would trigger an assert().
208d461b73eSRichard Henderson      */
209d461b73eSRichard Henderson     if (reserved_va != 0 &&
21095059f9cSRichard Henderson         TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE - 1 > reserved_va) {
211d461b73eSRichard Henderson         error_report("Cannot allocate vsyscall page");
212d461b73eSRichard Henderson         exit(EXIT_FAILURE);
213d461b73eSRichard Henderson     }
214d461b73eSRichard Henderson     page_set_flags(TARGET_VSYSCALL_PAGE,
21549840a4aSRichard Henderson                    TARGET_VSYSCALL_PAGE | ~TARGET_PAGE_MASK,
216d461b73eSRichard Henderson                    PAGE_EXEC | PAGE_VALID);
217d461b73eSRichard Henderson     return true;
218d461b73eSRichard Henderson }
219d461b73eSRichard Henderson #endif
22084409ddbSj_mayer #else
22184409ddbSj_mayer 
22230ac07d4Sbellard /*
22330ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
22430ac07d4Sbellard  */
22530ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
22630ac07d4Sbellard 
22730ac07d4Sbellard /*
22830ac07d4Sbellard  * These are used to set parameters in the core dumps.
22930ac07d4Sbellard  */
23030ac07d4Sbellard #define ELF_CLASS       ELFCLASS32
23130ac07d4Sbellard #define ELF_ARCH        EM_386
23230ac07d4Sbellard 
2339263ba84SRichard Henderson #define ELF_PLATFORM get_elf_platform()
234872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
2359263ba84SRichard Henderson 
2369263ba84SRichard Henderson static const char *get_elf_platform(void)
2379263ba84SRichard Henderson {
2389263ba84SRichard Henderson     static char elf_platform[] = "i386";
2399263ba84SRichard Henderson     int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
2409263ba84SRichard Henderson     if (family > 6) {
2419263ba84SRichard Henderson         family = 6;
2429263ba84SRichard Henderson     }
2439263ba84SRichard Henderson     if (family >= 3) {
2449263ba84SRichard Henderson         elf_platform[1] = '0' + family;
2459263ba84SRichard Henderson     }
2469263ba84SRichard Henderson     return elf_platform;
2479263ba84SRichard Henderson }
2489263ba84SRichard Henderson 
249d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
250d97ef72eSRichard Henderson                                struct image_info *infop)
251e5fe0c52Spbrook {
252e5fe0c52Spbrook     regs->esp = infop->start_stack;
253e5fe0c52Spbrook     regs->eip = infop->entry;
254e5fe0c52Spbrook 
25530ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
25630ac07d4Sbellard        starts %edx contains a pointer to a function which might be
25730ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
25830ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
25930ac07d4Sbellard        that have been loaded before the code runs.
26030ac07d4Sbellard 
26130ac07d4Sbellard        A value of 0 tells we have no such handler.  */
262e5fe0c52Spbrook     regs->edx = 0;
263b346ff46Sbellard }
2649edc5d79SMika Westerberg 
2659edc5d79SMika Westerberg #define ELF_NREG    17
266c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
2679edc5d79SMika Westerberg 
2689edc5d79SMika Westerberg /*
2699edc5d79SMika Westerberg  * Note that ELF_NREG should be 19 as there should be place for
2709edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
2719edc5d79SMika Westerberg  * those.
2729edc5d79SMika Westerberg  *
2739edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
2749edc5d79SMika Westerberg  */
27505390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
2769edc5d79SMika Westerberg {
277030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[R_EBX]);
278030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[R_ECX]);
279030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[R_EDX]);
280030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[R_ESI]);
281030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EDI]);
282030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBP]);
283030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[R_EAX]);
284030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->segs[R_DS].selector & 0xffff);
285030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->segs[R_ES].selector & 0xffff);
286030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->segs[R_FS].selector & 0xffff);
287030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->segs[R_GS].selector & 0xffff);
288030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_EAX]); /* XXX */
289030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->eip);
290030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->segs[R_CS].selector & 0xffff);
291030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->eflags);
292030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_ESP]);
293030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->segs[R_SS].selector & 0xffff);
2949edc5d79SMika Westerberg }
29584409ddbSj_mayer #endif
296b346ff46Sbellard 
2979edc5d79SMika Westerberg #define USE_ELF_CORE_DUMP
298b346ff46Sbellard #define ELF_EXEC_PAGESIZE       4096
299b346ff46Sbellard 
300b346ff46Sbellard #endif
301b346ff46Sbellard 
302b346ff46Sbellard #ifdef TARGET_ARM
303b346ff46Sbellard 
30424e76ff0SPeter Maydell #ifndef TARGET_AARCH64
30524e76ff0SPeter Maydell /* 32 bit ARM definitions */
30624e76ff0SPeter Maydell 
307b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_ARM
308b346ff46Sbellard #define ELF_CLASS       ELFCLASS32
309872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
310b346ff46Sbellard 
311d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
312d97ef72eSRichard Henderson                                struct image_info *infop)
313b346ff46Sbellard {
314992f48a0Sblueswir1     abi_long stack = infop->start_stack;
315b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
31699033caeSAlexander Graf 
317167e4cdcSPeter Maydell     regs->uregs[16] = ARM_CPU_MODE_USR;
318167e4cdcSPeter Maydell     if (infop->entry & 1) {
319167e4cdcSPeter Maydell         regs->uregs[16] |= CPSR_T;
320167e4cdcSPeter Maydell     }
321167e4cdcSPeter Maydell     regs->uregs[15] = infop->entry & 0xfffffffe;
322167e4cdcSPeter Maydell     regs->uregs[13] = infop->start_stack;
3232f619698Sbellard     /* FIXME - what to for failure of get_user()? */
324167e4cdcSPeter Maydell     get_user_ual(regs->uregs[2], stack + 8); /* envp */
325167e4cdcSPeter Maydell     get_user_ual(regs->uregs[1], stack + 4); /* envp */
326a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
327167e4cdcSPeter Maydell     regs->uregs[0] = 0;
328e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
329863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
330167e4cdcSPeter Maydell     regs->uregs[10] = infop->start_data;
3313cb10cfaSChristophe Lyon 
3323cb10cfaSChristophe Lyon     /* Support ARM FDPIC.  */
3333cb10cfaSChristophe Lyon     if (info_is_fdpic(infop)) {
3343cb10cfaSChristophe Lyon         /* As described in the ABI document, r7 points to the loadmap info
3353cb10cfaSChristophe Lyon          * prepared by the kernel. If an interpreter is needed, r8 points
3363cb10cfaSChristophe Lyon          * to the interpreter loadmap and r9 points to the interpreter
3373cb10cfaSChristophe Lyon          * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
3383cb10cfaSChristophe Lyon          * r9 points to the main program PT_DYNAMIC info.
3393cb10cfaSChristophe Lyon          */
3403cb10cfaSChristophe Lyon         regs->uregs[7] = infop->loadmap_addr;
3413cb10cfaSChristophe Lyon         if (infop->interpreter_loadmap_addr) {
3423cb10cfaSChristophe Lyon             /* Executable is dynamically loaded.  */
3433cb10cfaSChristophe Lyon             regs->uregs[8] = infop->interpreter_loadmap_addr;
3443cb10cfaSChristophe Lyon             regs->uregs[9] = infop->interpreter_pt_dynamic_addr;
3453cb10cfaSChristophe Lyon         } else {
3463cb10cfaSChristophe Lyon             regs->uregs[8] = 0;
3473cb10cfaSChristophe Lyon             regs->uregs[9] = infop->pt_dynamic_addr;
3483cb10cfaSChristophe Lyon         }
3493cb10cfaSChristophe Lyon     }
350b346ff46Sbellard }
351b346ff46Sbellard 
352edf8e2afSMika Westerberg #define ELF_NREG    18
353c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
354edf8e2afSMika Westerberg 
35505390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUARMState *env)
356edf8e2afSMika Westerberg {
35786cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->regs[0]);
35886cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->regs[1]);
35986cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->regs[2]);
36086cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->regs[3]);
36186cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->regs[4]);
36286cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->regs[5]);
36386cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->regs[6]);
36486cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->regs[7]);
36586cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->regs[8]);
36686cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->regs[9]);
36786cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->regs[10]);
36886cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->regs[11]);
36986cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->regs[12]);
37086cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->regs[13]);
37186cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->regs[14]);
37286cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->regs[15]);
373edf8e2afSMika Westerberg 
37486cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(cpsr_read((CPUARMState *)env));
37586cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->regs[0]); /* XXX */
376edf8e2afSMika Westerberg }
377edf8e2afSMika Westerberg 
37830ac07d4Sbellard #define USE_ELF_CORE_DUMP
37930ac07d4Sbellard #define ELF_EXEC_PAGESIZE       4096
38030ac07d4Sbellard 
381afce2927Sbellard enum
382afce2927Sbellard {
383afce2927Sbellard     ARM_HWCAP_ARM_SWP       = 1 << 0,
384afce2927Sbellard     ARM_HWCAP_ARM_HALF      = 1 << 1,
385afce2927Sbellard     ARM_HWCAP_ARM_THUMB     = 1 << 2,
386afce2927Sbellard     ARM_HWCAP_ARM_26BIT     = 1 << 3,
387afce2927Sbellard     ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
388afce2927Sbellard     ARM_HWCAP_ARM_FPA       = 1 << 5,
389afce2927Sbellard     ARM_HWCAP_ARM_VFP       = 1 << 6,
390afce2927Sbellard     ARM_HWCAP_ARM_EDSP      = 1 << 7,
391cf6de34aSRiku Voipio     ARM_HWCAP_ARM_JAVA      = 1 << 8,
392cf6de34aSRiku Voipio     ARM_HWCAP_ARM_IWMMXT    = 1 << 9,
39343ce393eSPeter Maydell     ARM_HWCAP_ARM_CRUNCH    = 1 << 10,
39443ce393eSPeter Maydell     ARM_HWCAP_ARM_THUMBEE   = 1 << 11,
39543ce393eSPeter Maydell     ARM_HWCAP_ARM_NEON      = 1 << 12,
39643ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3     = 1 << 13,
39743ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3D16  = 1 << 14,
39824682654SPeter Maydell     ARM_HWCAP_ARM_TLS       = 1 << 15,
39924682654SPeter Maydell     ARM_HWCAP_ARM_VFPv4     = 1 << 16,
40024682654SPeter Maydell     ARM_HWCAP_ARM_IDIVA     = 1 << 17,
40124682654SPeter Maydell     ARM_HWCAP_ARM_IDIVT     = 1 << 18,
40224682654SPeter Maydell     ARM_HWCAP_ARM_VFPD32    = 1 << 19,
40324682654SPeter Maydell     ARM_HWCAP_ARM_LPAE      = 1 << 20,
40424682654SPeter Maydell     ARM_HWCAP_ARM_EVTSTRM   = 1 << 21,
40523d7f14dSPeter Maydell     ARM_HWCAP_ARM_FPHP      = 1 << 22,
40623d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDHP   = 1 << 23,
40723d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDDP   = 1 << 24,
40823d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDFHM  = 1 << 25,
40923d7f14dSPeter Maydell     ARM_HWCAP_ARM_ASIMDBF16 = 1 << 26,
41023d7f14dSPeter Maydell     ARM_HWCAP_ARM_I8MM      = 1 << 27,
411afce2927Sbellard };
412afce2927Sbellard 
413ad6919dcSPeter Maydell enum {
414ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_AES      = 1 << 0,
415ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_PMULL    = 1 << 1,
416ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA1     = 1 << 2,
417ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_SHA2     = 1 << 3,
418ad6919dcSPeter Maydell     ARM_HWCAP2_ARM_CRC32    = 1 << 4,
41923d7f14dSPeter Maydell     ARM_HWCAP2_ARM_SB       = 1 << 5,
42023d7f14dSPeter Maydell     ARM_HWCAP2_ARM_SSBS     = 1 << 6,
421ad6919dcSPeter Maydell };
422ad6919dcSPeter Maydell 
4236b1275ffSPeter Maydell /* The commpage only exists for 32 bit kernels */
4246b1275ffSPeter Maydell 
42566346fafSRichard Henderson #define HI_COMMPAGE (intptr_t)0xffff0f00u
426ee947430SAlex Bennée 
427ee947430SAlex Bennée static bool init_guest_commpage(void)
42897cc7560SDr. David Alan Gilbert {
429d713cf4dSPhilippe Mathieu-Daudé     ARMCPU *cpu = ARM_CPU(thread_cpu);
430d713cf4dSPhilippe Mathieu-Daudé     abi_ptr commpage;
431d713cf4dSPhilippe Mathieu-Daudé     void *want;
432d713cf4dSPhilippe Mathieu-Daudé     void *addr;
433d713cf4dSPhilippe Mathieu-Daudé 
434d713cf4dSPhilippe Mathieu-Daudé     /*
435d713cf4dSPhilippe Mathieu-Daudé      * M-profile allocates maximum of 2GB address space, so can never
436d713cf4dSPhilippe Mathieu-Daudé      * allocate the commpage.  Skip it.
437d713cf4dSPhilippe Mathieu-Daudé      */
438d713cf4dSPhilippe Mathieu-Daudé     if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
439d713cf4dSPhilippe Mathieu-Daudé         return true;
440d713cf4dSPhilippe Mathieu-Daudé     }
441d713cf4dSPhilippe Mathieu-Daudé 
442d713cf4dSPhilippe Mathieu-Daudé     commpage = HI_COMMPAGE & -qemu_host_page_size;
443d713cf4dSPhilippe Mathieu-Daudé     want = g2h_untagged(commpage);
444d713cf4dSPhilippe Mathieu-Daudé     addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
4455c3e87f3SAlex Bennée                 MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
44697cc7560SDr. David Alan Gilbert 
4476cda41daSRichard Henderson     if (addr == MAP_FAILED) {
448ee947430SAlex Bennée         perror("Allocating guest commpage");
449ee947430SAlex Bennée         exit(EXIT_FAILURE);
450ee947430SAlex Bennée     }
451ee947430SAlex Bennée     if (addr != want) {
452ee947430SAlex Bennée         return false;
453806d1021SMeador Inge     }
454806d1021SMeador Inge 
455ee947430SAlex Bennée     /* Set kernel helper versions; rest of page is 0.  */
4566cda41daSRichard Henderson     __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu));
45797cc7560SDr. David Alan Gilbert 
4586cda41daSRichard Henderson     if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
45997cc7560SDr. David Alan Gilbert         perror("Protecting guest commpage");
460ee947430SAlex Bennée         exit(EXIT_FAILURE);
46197cc7560SDr. David Alan Gilbert     }
4626cda41daSRichard Henderson 
4636cda41daSRichard Henderson     page_set_flags(commpage, commpage | ~qemu_host_page_mask,
4646cda41daSRichard Henderson                    PAGE_READ | PAGE_EXEC | PAGE_VALID);
465ee947430SAlex Bennée     return true;
46697cc7560SDr. David Alan Gilbert }
467adf050b1SBenoit Canet 
468adf050b1SBenoit Canet #define ELF_HWCAP get_elf_hwcap()
469ad6919dcSPeter Maydell #define ELF_HWCAP2 get_elf_hwcap2()
470adf050b1SBenoit Canet 
471a55b9e72SHelge Deller uint32_t get_elf_hwcap(void)
472adf050b1SBenoit Canet {
473a2247f8eSAndreas Färber     ARMCPU *cpu = ARM_CPU(thread_cpu);
474adf050b1SBenoit Canet     uint32_t hwcaps = 0;
475adf050b1SBenoit Canet 
476adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_SWP;
477adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_HALF;
478adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_THUMB;
479adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
480adf050b1SBenoit Canet 
481adf050b1SBenoit Canet     /* probe for the extra features */
482adf050b1SBenoit Canet #define GET_FEATURE(feat, hwcap) \
483a2247f8eSAndreas Färber     do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
484962fcbf2SRichard Henderson 
485962fcbf2SRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
486962fcbf2SRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
487962fcbf2SRichard Henderson 
48824682654SPeter Maydell     /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
48924682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
490adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
491adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
492adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
49324682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
494bfa8a370SRichard Henderson     GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
495873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
496873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
497bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP);
498bfa8a370SRichard Henderson 
499bfa8a370SRichard Henderson     if (cpu_isar_feature(aa32_fpsp_v3, cpu) ||
500bfa8a370SRichard Henderson         cpu_isar_feature(aa32_fpdp_v3, cpu)) {
501bfa8a370SRichard Henderson         hwcaps |= ARM_HWCAP_ARM_VFPv3;
502bfa8a370SRichard Henderson         if (cpu_isar_feature(aa32_simd_r32, cpu)) {
503bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPD32;
504bfa8a370SRichard Henderson         } else {
505bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPv3D16;
506bfa8a370SRichard Henderson         }
507bfa8a370SRichard Henderson     }
508bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4);
509429b7e01SPeter Maydell     /*
510429b7e01SPeter Maydell      * MVFR1.FPHP and .SIMDHP must be in sync, and QEMU uses the same
511429b7e01SPeter Maydell      * isar_feature function for both. The kernel reports them as two hwcaps.
512429b7e01SPeter Maydell      */
513429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_FPHP);
514429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fp16_arith, ARM_HWCAP_ARM_ASIMDHP);
515429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_dp, ARM_HWCAP_ARM_ASIMDDP);
516429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_fhm, ARM_HWCAP_ARM_ASIMDFHM);
517429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_bf16, ARM_HWCAP_ARM_ASIMDBF16);
518429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_i8mm, ARM_HWCAP_ARM_I8MM);
519adf050b1SBenoit Canet 
520adf050b1SBenoit Canet     return hwcaps;
521adf050b1SBenoit Canet }
522afce2927Sbellard 
523a55b9e72SHelge Deller uint32_t get_elf_hwcap2(void)
524ad6919dcSPeter Maydell {
525ad6919dcSPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
526ad6919dcSPeter Maydell     uint32_t hwcaps = 0;
527ad6919dcSPeter Maydell 
528962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_aes, ARM_HWCAP2_ARM_AES);
529962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_pmull, ARM_HWCAP2_ARM_PMULL);
530962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha1, ARM_HWCAP2_ARM_SHA1);
531962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha2, ARM_HWCAP2_ARM_SHA2);
532962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_crc32, ARM_HWCAP2_ARM_CRC32);
533429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_sb, ARM_HWCAP2_ARM_SB);
534429b7e01SPeter Maydell     GET_FEATURE_ID(aa32_ssbs, ARM_HWCAP2_ARM_SSBS);
535ad6919dcSPeter Maydell     return hwcaps;
536ad6919dcSPeter Maydell }
537ad6919dcSPeter Maydell 
538a55b9e72SHelge Deller const char *elf_hwcap_str(uint32_t bit)
539a55b9e72SHelge Deller {
540a55b9e72SHelge Deller     static const char *hwcap_str[] = {
541a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_SWP      )] = "swp",
542a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_HALF     )] = "half",
543a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_THUMB    )] = "thumb",
544a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_26BIT    )] = "26bit",
545a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_FAST_MULT)] = "fast_mult",
546a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_FPA      )] = "fpa",
547a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFP      )] = "vfp",
548a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_EDSP     )] = "edsp",
549a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_JAVA     )] = "java",
550a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IWMMXT   )] = "iwmmxt",
551a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_CRUNCH   )] = "crunch",
552a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_THUMBEE  )] = "thumbee",
553a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_NEON     )] = "neon",
554a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv3    )] = "vfpv3",
555a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv3D16 )] = "vfpv3d16",
556a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_TLS      )] = "tls",
557a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPv4    )] = "vfpv4",
558a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IDIVA    )] = "idiva",
559a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_IDIVT    )] = "idivt",
560a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_VFPD32   )] = "vfpd32",
561a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_LPAE     )] = "lpae",
562a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_ARM_EVTSTRM  )] = "evtstrm",
56323d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_FPHP     )] = "fphp",
56423d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDHP  )] = "asimdhp",
56523d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDDP  )] = "asimddp",
56623d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDFHM )] = "asimdfhm",
56723d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_ASIMDBF16)] = "asimdbf16",
56823d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP_ARM_I8MM     )] = "i8mm",
569a55b9e72SHelge Deller     };
570a55b9e72SHelge Deller 
571a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
572a55b9e72SHelge Deller }
573a55b9e72SHelge Deller 
574a55b9e72SHelge Deller const char *elf_hwcap2_str(uint32_t bit)
575a55b9e72SHelge Deller {
576a55b9e72SHelge Deller     static const char *hwcap_str[] = {
577a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_AES  )] = "aes",
578a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_PMULL)] = "pmull",
579a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_SHA1 )] = "sha1",
580a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_SHA2 )] = "sha2",
581a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_ARM_CRC32)] = "crc32",
58223d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_ARM_SB   )] = "sb",
58323d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_ARM_SSBS )] = "ssbs",
584a55b9e72SHelge Deller     };
585a55b9e72SHelge Deller 
586a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
587a55b9e72SHelge Deller }
588a55b9e72SHelge Deller 
589ad6919dcSPeter Maydell #undef GET_FEATURE
590962fcbf2SRichard Henderson #undef GET_FEATURE_ID
591ad6919dcSPeter Maydell 
59213ec4ec3SRichard Henderson #define ELF_PLATFORM get_elf_platform()
59313ec4ec3SRichard Henderson 
59413ec4ec3SRichard Henderson static const char *get_elf_platform(void)
59513ec4ec3SRichard Henderson {
596b77af26eSRichard Henderson     CPUARMState *env = cpu_env(thread_cpu);
59713ec4ec3SRichard Henderson 
598ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
59913ec4ec3SRichard Henderson # define END  "b"
60013ec4ec3SRichard Henderson #else
60113ec4ec3SRichard Henderson # define END  "l"
60213ec4ec3SRichard Henderson #endif
60313ec4ec3SRichard Henderson 
60413ec4ec3SRichard Henderson     if (arm_feature(env, ARM_FEATURE_V8)) {
60513ec4ec3SRichard Henderson         return "v8" END;
60613ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V7)) {
60713ec4ec3SRichard Henderson         if (arm_feature(env, ARM_FEATURE_M)) {
60813ec4ec3SRichard Henderson             return "v7m" END;
60913ec4ec3SRichard Henderson         } else {
61013ec4ec3SRichard Henderson             return "v7" END;
61113ec4ec3SRichard Henderson         }
61213ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V6)) {
61313ec4ec3SRichard Henderson         return "v6" END;
61413ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V5)) {
61513ec4ec3SRichard Henderson         return "v5" END;
61613ec4ec3SRichard Henderson     } else {
61713ec4ec3SRichard Henderson         return "v4" END;
61813ec4ec3SRichard Henderson     }
61913ec4ec3SRichard Henderson 
62013ec4ec3SRichard Henderson #undef END
62113ec4ec3SRichard Henderson }
62213ec4ec3SRichard Henderson 
62324e76ff0SPeter Maydell #else
62424e76ff0SPeter Maydell /* 64 bit ARM definitions */
62524e76ff0SPeter Maydell 
626b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_AARCH64
62724e76ff0SPeter Maydell #define ELF_CLASS       ELFCLASS64
628ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
629e20e3ec9SRichard Henderson # define ELF_PLATFORM    "aarch64_be"
630e20e3ec9SRichard Henderson #else
63124e76ff0SPeter Maydell # define ELF_PLATFORM    "aarch64"
632e20e3ec9SRichard Henderson #endif
63324e76ff0SPeter Maydell 
63424e76ff0SPeter Maydell static inline void init_thread(struct target_pt_regs *regs,
63524e76ff0SPeter Maydell                                struct image_info *infop)
63624e76ff0SPeter Maydell {
63724e76ff0SPeter Maydell     abi_long stack = infop->start_stack;
63824e76ff0SPeter Maydell     memset(regs, 0, sizeof(*regs));
63924e76ff0SPeter Maydell 
64024e76ff0SPeter Maydell     regs->pc = infop->entry & ~0x3ULL;
64124e76ff0SPeter Maydell     regs->sp = stack;
64224e76ff0SPeter Maydell }
64324e76ff0SPeter Maydell 
64424e76ff0SPeter Maydell #define ELF_NREG    34
64524e76ff0SPeter Maydell typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
64624e76ff0SPeter Maydell 
64724e76ff0SPeter Maydell static void elf_core_copy_regs(target_elf_gregset_t *regs,
64824e76ff0SPeter Maydell                                const CPUARMState *env)
64924e76ff0SPeter Maydell {
65024e76ff0SPeter Maydell     int i;
65124e76ff0SPeter Maydell 
65224e76ff0SPeter Maydell     for (i = 0; i < 32; i++) {
65324e76ff0SPeter Maydell         (*regs)[i] = tswapreg(env->xregs[i]);
65424e76ff0SPeter Maydell     }
65524e76ff0SPeter Maydell     (*regs)[32] = tswapreg(env->pc);
65624e76ff0SPeter Maydell     (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env));
65724e76ff0SPeter Maydell }
65824e76ff0SPeter Maydell 
65924e76ff0SPeter Maydell #define USE_ELF_CORE_DUMP
66024e76ff0SPeter Maydell #define ELF_EXEC_PAGESIZE       4096
66124e76ff0SPeter Maydell 
66224e76ff0SPeter Maydell enum {
66324e76ff0SPeter Maydell     ARM_HWCAP_A64_FP            = 1 << 0,
66424e76ff0SPeter Maydell     ARM_HWCAP_A64_ASIMD         = 1 << 1,
66524e76ff0SPeter Maydell     ARM_HWCAP_A64_EVTSTRM       = 1 << 2,
66624e76ff0SPeter Maydell     ARM_HWCAP_A64_AES           = 1 << 3,
66724e76ff0SPeter Maydell     ARM_HWCAP_A64_PMULL         = 1 << 4,
66824e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA1          = 1 << 5,
66924e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA2          = 1 << 6,
67024e76ff0SPeter Maydell     ARM_HWCAP_A64_CRC32         = 1 << 7,
671955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ATOMICS       = 1 << 8,
672955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FPHP          = 1 << 9,
673955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDHP       = 1 << 10,
674955f56d4SArd Biesheuvel     ARM_HWCAP_A64_CPUID         = 1 << 11,
675955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDRDM      = 1 << 12,
676955f56d4SArd Biesheuvel     ARM_HWCAP_A64_JSCVT         = 1 << 13,
677955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FCMA          = 1 << 14,
678955f56d4SArd Biesheuvel     ARM_HWCAP_A64_LRCPC         = 1 << 15,
679955f56d4SArd Biesheuvel     ARM_HWCAP_A64_DCPOP         = 1 << 16,
680955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA3          = 1 << 17,
681955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM3           = 1 << 18,
682955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM4           = 1 << 19,
683955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDDP       = 1 << 20,
684955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA512        = 1 << 21,
685955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SVE           = 1 << 22,
6860083a1faSRichard Henderson     ARM_HWCAP_A64_ASIMDFHM      = 1 << 23,
6870083a1faSRichard Henderson     ARM_HWCAP_A64_DIT           = 1 << 24,
6880083a1faSRichard Henderson     ARM_HWCAP_A64_USCAT         = 1 << 25,
6890083a1faSRichard Henderson     ARM_HWCAP_A64_ILRCPC        = 1 << 26,
6900083a1faSRichard Henderson     ARM_HWCAP_A64_FLAGM         = 1 << 27,
6910083a1faSRichard Henderson     ARM_HWCAP_A64_SSBS          = 1 << 28,
6920083a1faSRichard Henderson     ARM_HWCAP_A64_SB            = 1 << 29,
6930083a1faSRichard Henderson     ARM_HWCAP_A64_PACA          = 1 << 30,
6940083a1faSRichard Henderson     ARM_HWCAP_A64_PACG          = 1UL << 31,
6952041df4aSRichard Henderson 
6962041df4aSRichard Henderson     ARM_HWCAP2_A64_DCPODP       = 1 << 0,
6972041df4aSRichard Henderson     ARM_HWCAP2_A64_SVE2         = 1 << 1,
6982041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEAES       = 1 << 2,
6992041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEPMULL     = 1 << 3,
7002041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEBITPERM   = 1 << 4,
7012041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESHA3      = 1 << 5,
7022041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESM4       = 1 << 6,
7032041df4aSRichard Henderson     ARM_HWCAP2_A64_FLAGM2       = 1 << 7,
7042041df4aSRichard Henderson     ARM_HWCAP2_A64_FRINT        = 1 << 8,
70568948d18SRichard Henderson     ARM_HWCAP2_A64_SVEI8MM      = 1 << 9,
70668948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF32MM     = 1 << 10,
70768948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF64MM     = 1 << 11,
70868948d18SRichard Henderson     ARM_HWCAP2_A64_SVEBF16      = 1 << 12,
70968948d18SRichard Henderson     ARM_HWCAP2_A64_I8MM         = 1 << 13,
71068948d18SRichard Henderson     ARM_HWCAP2_A64_BF16         = 1 << 14,
71168948d18SRichard Henderson     ARM_HWCAP2_A64_DGH          = 1 << 15,
71268948d18SRichard Henderson     ARM_HWCAP2_A64_RNG          = 1 << 16,
71368948d18SRichard Henderson     ARM_HWCAP2_A64_BTI          = 1 << 17,
71468948d18SRichard Henderson     ARM_HWCAP2_A64_MTE          = 1 << 18,
715f9982ceaSRichard Henderson     ARM_HWCAP2_A64_ECV          = 1 << 19,
716f9982ceaSRichard Henderson     ARM_HWCAP2_A64_AFP          = 1 << 20,
717f9982ceaSRichard Henderson     ARM_HWCAP2_A64_RPRES        = 1 << 21,
718f9982ceaSRichard Henderson     ARM_HWCAP2_A64_MTE3         = 1 << 22,
719f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME          = 1 << 23,
720f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I16I64   = 1 << 24,
721f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F64F64   = 1 << 25,
722f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I8I32    = 1 << 26,
723f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F16F32   = 1 << 27,
724f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_B16F32   = 1 << 28,
725f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F32F32   = 1 << 29,
726f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_FA64     = 1 << 30,
72723d7f14dSPeter Maydell     ARM_HWCAP2_A64_WFXT         = 1ULL << 31,
72823d7f14dSPeter Maydell     ARM_HWCAP2_A64_EBF16        = 1ULL << 32,
72923d7f14dSPeter Maydell     ARM_HWCAP2_A64_SVE_EBF16    = 1ULL << 33,
73023d7f14dSPeter Maydell     ARM_HWCAP2_A64_CSSC         = 1ULL << 34,
73123d7f14dSPeter Maydell     ARM_HWCAP2_A64_RPRFM        = 1ULL << 35,
73223d7f14dSPeter Maydell     ARM_HWCAP2_A64_SVE2P1       = 1ULL << 36,
73323d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME2         = 1ULL << 37,
73423d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME2P1       = 1ULL << 38,
73523d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_I16I32   = 1ULL << 39,
73623d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_BI32I32  = 1ULL << 40,
73723d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_B16B16   = 1ULL << 41,
73823d7f14dSPeter Maydell     ARM_HWCAP2_A64_SME_F16F16   = 1ULL << 42,
73923d7f14dSPeter Maydell     ARM_HWCAP2_A64_MOPS         = 1ULL << 43,
74023d7f14dSPeter Maydell     ARM_HWCAP2_A64_HBC          = 1ULL << 44,
74124e76ff0SPeter Maydell };
74224e76ff0SPeter Maydell 
74324e76ff0SPeter Maydell #define ELF_HWCAP   get_elf_hwcap()
7442041df4aSRichard Henderson #define ELF_HWCAP2  get_elf_hwcap2()
7452041df4aSRichard Henderson 
7462041df4aSRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
7472041df4aSRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
74824e76ff0SPeter Maydell 
749a55b9e72SHelge Deller uint32_t get_elf_hwcap(void)
75024e76ff0SPeter Maydell {
75124e76ff0SPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
75224e76ff0SPeter Maydell     uint32_t hwcaps = 0;
75324e76ff0SPeter Maydell 
75424e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_FP;
75524e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_ASIMD;
75637020ff1SAlex Bennée     hwcaps |= ARM_HWCAP_A64_CPUID;
75724e76ff0SPeter Maydell 
75824e76ff0SPeter Maydell     /* probe for the extra features */
759962fcbf2SRichard Henderson 
760962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES);
761962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL);
762962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha1, ARM_HWCAP_A64_SHA1);
763962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha256, ARM_HWCAP_A64_SHA2);
764962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha512, ARM_HWCAP_A64_SHA512);
765962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_crc32, ARM_HWCAP_A64_CRC32);
766962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha3, ARM_HWCAP_A64_SHA3);
767962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm3, ARM_HWCAP_A64_SM3);
768962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm4, ARM_HWCAP_A64_SM4);
7695763190fSRichard Henderson     GET_FEATURE_ID(aa64_fp16, ARM_HWCAP_A64_FPHP | ARM_HWCAP_A64_ASIMDHP);
770962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_atomics, ARM_HWCAP_A64_ATOMICS);
771962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_rdm, ARM_HWCAP_A64_ASIMDRDM);
772962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_dp, ARM_HWCAP_A64_ASIMDDP);
773962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA);
774cd208a1cSRichard Henderson     GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE);
77529d26ab2SRichard Henderson     GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG);
7761c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM);
7771c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
7789888bd1eSRichard Henderson     GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
779b89d9c98SRichard Henderson     GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
7800d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
7812677cf9fSPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
782a1229109SPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
783962fcbf2SRichard Henderson 
7842041df4aSRichard Henderson     return hwcaps;
7852041df4aSRichard Henderson }
7862041df4aSRichard Henderson 
787a55b9e72SHelge Deller uint32_t get_elf_hwcap2(void)
7882041df4aSRichard Henderson {
7892041df4aSRichard Henderson     ARMCPU *cpu = ARM_CPU(thread_cpu);
7902041df4aSRichard Henderson     uint32_t hwcaps = 0;
7912041df4aSRichard Henderson 
7920d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
793cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2, ARM_HWCAP2_A64_SVE2);
794cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_aes, ARM_HWCAP2_A64_SVEAES);
795cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_pmull128, ARM_HWCAP2_A64_SVEPMULL);
796cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_bitperm, ARM_HWCAP2_A64_SVEBITPERM);
797cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sha3, ARM_HWCAP2_A64_SVESHA3);
798cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sm4, ARM_HWCAP2_A64_SVESM4);
7992041df4aSRichard Henderson     GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
8002041df4aSRichard Henderson     GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
801cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_i8mm, ARM_HWCAP2_A64_SVEI8MM);
802cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f32mm, ARM_HWCAP2_A64_SVEF32MM);
803cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f64mm, ARM_HWCAP2_A64_SVEF64MM);
8046c47a905SRichard Henderson     GET_FEATURE_ID(aa64_sve_bf16, ARM_HWCAP2_A64_SVEBF16);
805cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_i8mm, ARM_HWCAP2_A64_I8MM);
8066c47a905SRichard Henderson     GET_FEATURE_ID(aa64_bf16, ARM_HWCAP2_A64_BF16);
80768948d18SRichard Henderson     GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG);
80868948d18SRichard Henderson     GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI);
80968948d18SRichard Henderson     GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE);
810f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme, (ARM_HWCAP2_A64_SME |
811f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F32F32 |
812f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_B16F32 |
813f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F16F32 |
814f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_I8I32));
815f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_f64f64, ARM_HWCAP2_A64_SME_F64F64);
816f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_i16i64, ARM_HWCAP2_A64_SME_I16I64);
817f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_fa64, ARM_HWCAP2_A64_SME_FA64);
8183039b090SPeter Maydell     GET_FEATURE_ID(aa64_hbc, ARM_HWCAP2_A64_HBC);
819706a92fbSPeter Maydell     GET_FEATURE_ID(aa64_mops, ARM_HWCAP2_A64_MOPS);
82024e76ff0SPeter Maydell 
82124e76ff0SPeter Maydell     return hwcaps;
82224e76ff0SPeter Maydell }
82324e76ff0SPeter Maydell 
824a55b9e72SHelge Deller const char *elf_hwcap_str(uint32_t bit)
825a55b9e72SHelge Deller {
826a55b9e72SHelge Deller     static const char *hwcap_str[] = {
827a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FP      )] = "fp",
828a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMD   )] = "asimd",
829a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_EVTSTRM )] = "evtstrm",
830a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_AES     )] = "aes",
831a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PMULL   )] = "pmull",
832a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA1    )] = "sha1",
833a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA2    )] = "sha2",
834a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_CRC32   )] = "crc32",
835a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ATOMICS )] = "atomics",
836a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FPHP    )] = "fphp",
837a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDHP )] = "asimdhp",
838a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_CPUID   )] = "cpuid",
839a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDRDM)] = "asimdrdm",
840a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_JSCVT   )] = "jscvt",
841a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FCMA    )] = "fcma",
842a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_LRCPC   )] = "lrcpc",
843a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_DCPOP   )] = "dcpop",
844a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA3    )] = "sha3",
845a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SM3     )] = "sm3",
846a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SM4     )] = "sm4",
847a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDDP )] = "asimddp",
848a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SHA512  )] = "sha512",
849a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SVE     )] = "sve",
850a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ASIMDFHM)] = "asimdfhm",
851a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_DIT     )] = "dit",
852a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_USCAT   )] = "uscat",
853a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_ILRCPC  )] = "ilrcpc",
854a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_FLAGM   )] = "flagm",
855a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SSBS    )] = "ssbs",
856a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_SB      )] = "sb",
857a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PACA    )] = "paca",
858a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP_A64_PACG    )] = "pacg",
859a55b9e72SHelge Deller     };
860a55b9e72SHelge Deller 
861a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
862a55b9e72SHelge Deller }
863a55b9e72SHelge Deller 
864a55b9e72SHelge Deller const char *elf_hwcap2_str(uint32_t bit)
865a55b9e72SHelge Deller {
866a55b9e72SHelge Deller     static const char *hwcap_str[] = {
867a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_DCPODP       )] = "dcpodp",
868a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVE2         )] = "sve2",
869a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEAES       )] = "sveaes",
870a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEPMULL     )] = "svepmull",
871a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEBITPERM   )] = "svebitperm",
872a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVESHA3      )] = "svesha3",
873a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVESM4       )] = "svesm4",
874a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_FLAGM2       )] = "flagm2",
875a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_FRINT        )] = "frint",
876a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEI8MM      )] = "svei8mm",
877a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEF32MM     )] = "svef32mm",
878a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEF64MM     )] = "svef64mm",
879a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SVEBF16      )] = "svebf16",
880a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_I8MM         )] = "i8mm",
881a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_BF16         )] = "bf16",
882a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_DGH          )] = "dgh",
883a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_RNG          )] = "rng",
884a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_BTI          )] = "bti",
885a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_MTE          )] = "mte",
886a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_ECV          )] = "ecv",
887a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_AFP          )] = "afp",
888a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_RPRES        )] = "rpres",
889a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_MTE3         )] = "mte3",
890a55b9e72SHelge Deller     [__builtin_ctz(ARM_HWCAP2_A64_SME          )] = "sme",
891e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_I16I64   )] = "smei16i64",
892e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F64F64   )] = "smef64f64",
893e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_I8I32    )] = "smei8i32",
894e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F16F32   )] = "smef16f32",
895e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_B16F32   )] = "smeb16f32",
896e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_F32F32   )] = "smef32f32",
897e2e40a77SPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_SME_FA64     )] = "smefa64",
89823d7f14dSPeter Maydell     [__builtin_ctz(ARM_HWCAP2_A64_WFXT         )] = "wfxt",
89923d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_EBF16      )] = "ebf16",
90023d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SVE_EBF16  )] = "sveebf16",
90123d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_CSSC       )] = "cssc",
90223d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_RPRFM      )] = "rprfm",
90323d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SVE2P1     )] = "sve2p1",
90423d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME2       )] = "sme2",
90523d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME2P1     )] = "sme2p1",
90623d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_I16I32 )] = "smei16i32",
90723d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_BI32I32)] = "smebi32i32",
90823d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_B16B16 )] = "smeb16b16",
90923d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_SME_F16F16 )] = "smef16f16",
91023d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_MOPS       )] = "mops",
91123d7f14dSPeter Maydell     [__builtin_ctzll(ARM_HWCAP2_A64_HBC        )] = "hbc",
912a55b9e72SHelge Deller     };
913a55b9e72SHelge Deller 
914a55b9e72SHelge Deller     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
915a55b9e72SHelge Deller }
916a55b9e72SHelge Deller 
9172041df4aSRichard Henderson #undef GET_FEATURE_ID
9182041df4aSRichard Henderson 
91924e76ff0SPeter Maydell #endif /* not TARGET_AARCH64 */
92024e76ff0SPeter Maydell #endif /* TARGET_ARM */
92130ac07d4Sbellard 
922853d6f7aSbellard #ifdef TARGET_SPARC
923a315a145Sbellard #ifdef TARGET_SPARC64
924853d6f7aSbellard 
925cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
926cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV | HWCAP_SPARC_V9)
927992f48a0Sblueswir1 #ifndef TARGET_ABI32
928cb33da57Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
929992f48a0Sblueswir1 #else
930992f48a0Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
931992f48a0Sblueswir1 #endif
932853d6f7aSbellard 
933a315a145Sbellard #define ELF_CLASS   ELFCLASS64
9345ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
935a315a145Sbellard #else
936cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
937cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV)
938853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
939853d6f7aSbellard #define ELF_ARCH    EM_SPARC
940089a2256SRichard Henderson #endif /* TARGET_SPARC64 */
941853d6f7aSbellard 
942d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
943d97ef72eSRichard Henderson                                struct image_info *infop)
944853d6f7aSbellard {
945089a2256SRichard Henderson     /* Note that target_cpu_copy_regs does not read psr/tstate. */
946f5155289Sbellard     regs->pc = infop->entry;
947f5155289Sbellard     regs->npc = regs->pc + 4;
948f5155289Sbellard     regs->y = 0;
949089a2256SRichard Henderson     regs->u_regs[14] = (infop->start_stack - 16 * sizeof(abi_ulong)
950089a2256SRichard Henderson                         - TARGET_STACK_BIAS);
951853d6f7aSbellard }
952089a2256SRichard Henderson #endif /* TARGET_SPARC */
953853d6f7aSbellard 
95467867308Sbellard #ifdef TARGET_PPC
95567867308Sbellard 
9564ecd4d16SPeter Crosthwaite #define ELF_MACHINE    PPC_ELF_MACHINE
95767867308Sbellard 
95874154d7eSThomas Huth #if defined(TARGET_PPC64)
95984409ddbSj_mayer 
96084409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
96184409ddbSj_mayer 
96284409ddbSj_mayer #define ELF_CLASS       ELFCLASS64
96384409ddbSj_mayer 
96484409ddbSj_mayer #else
96584409ddbSj_mayer 
96667867308Sbellard #define ELF_CLASS       ELFCLASS32
967872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
96884409ddbSj_mayer 
96984409ddbSj_mayer #endif
97084409ddbSj_mayer 
97167867308Sbellard #define ELF_ARCH        EM_PPC
97267867308Sbellard 
973df84e4f3SNathan Froyd /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
974df84e4f3SNathan Froyd    See arch/powerpc/include/asm/cputable.h.  */
975df84e4f3SNathan Froyd enum {
9763efa9a67Smalc     QEMU_PPC_FEATURE_32 = 0x80000000,
9773efa9a67Smalc     QEMU_PPC_FEATURE_64 = 0x40000000,
9783efa9a67Smalc     QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
9793efa9a67Smalc     QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
9803efa9a67Smalc     QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
9813efa9a67Smalc     QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
9823efa9a67Smalc     QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
9833efa9a67Smalc     QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
9843efa9a67Smalc     QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
9853efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
9863efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
9873efa9a67Smalc     QEMU_PPC_FEATURE_NO_TB = 0x00100000,
9883efa9a67Smalc     QEMU_PPC_FEATURE_POWER4 = 0x00080000,
9893efa9a67Smalc     QEMU_PPC_FEATURE_POWER5 = 0x00040000,
9903efa9a67Smalc     QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
9913efa9a67Smalc     QEMU_PPC_FEATURE_CELL = 0x00010000,
9923efa9a67Smalc     QEMU_PPC_FEATURE_BOOKE = 0x00008000,
9933efa9a67Smalc     QEMU_PPC_FEATURE_SMT = 0x00004000,
9943efa9a67Smalc     QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
9953efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
9963efa9a67Smalc     QEMU_PPC_FEATURE_PA6T = 0x00000800,
9973efa9a67Smalc     QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
9983efa9a67Smalc     QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
9993efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
10003efa9a67Smalc     QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
10013efa9a67Smalc     QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
1002df84e4f3SNathan Froyd 
10033efa9a67Smalc     QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
10043efa9a67Smalc     QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
1005a60438ddSTom Musta 
1006a60438ddSTom Musta     /* Feature definitions in AT_HWCAP2.  */
1007a60438ddSTom Musta     QEMU_PPC_FEATURE2_ARCH_2_07 = 0x80000000, /* ISA 2.07 */
1008a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_HTM = 0x40000000, /* Hardware Transactional Memory */
1009a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_DSCR = 0x20000000, /* Data Stream Control Register */
1010a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */
1011a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */
1012a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */
101324c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_VEC_CRYPTO = 0x02000000,
101424c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NOSC = 0x01000000,
1015be0c46d4SSandipan Das     QEMU_PPC_FEATURE2_ARCH_3_00 = 0x00800000, /* ISA 3.00 */
101624c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HAS_IEEE128 = 0x00400000, /* VSX IEEE Bin Float 128-bit */
101724c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */
101824c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */
101924c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */
102096c343ccSJoel Stanley     QEMU_PPC_FEATURE2_ARCH_3_1 = 0x00040000, /* ISA 3.1 */
102196c343ccSJoel Stanley     QEMU_PPC_FEATURE2_MMA = 0x00020000, /* Matrix-Multiply Assist */
1022df84e4f3SNathan Froyd };
1023df84e4f3SNathan Froyd 
1024df84e4f3SNathan Froyd #define ELF_HWCAP get_elf_hwcap()
1025df84e4f3SNathan Froyd 
1026df84e4f3SNathan Froyd static uint32_t get_elf_hwcap(void)
1027df84e4f3SNathan Froyd {
1028a2247f8eSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
1029df84e4f3SNathan Froyd     uint32_t features = 0;
1030df84e4f3SNathan Froyd 
1031df84e4f3SNathan Froyd     /* We don't have to be terribly complete here; the high points are
1032df84e4f3SNathan Froyd        Altivec/FP/SPE support.  Anything else is just a bonus.  */
1033df84e4f3SNathan Froyd #define GET_FEATURE(flag, feature)                                      \
1034a2247f8eSAndreas Färber     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
103558eb5308SMichael Walle #define GET_FEATURE2(flags, feature) \
103658eb5308SMichael Walle     do { \
103758eb5308SMichael Walle         if ((cpu->env.insns_flags2 & flags) == flags) { \
103858eb5308SMichael Walle             features |= feature; \
103958eb5308SMichael Walle         } \
104058eb5308SMichael Walle     } while (0)
10413efa9a67Smalc     GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
10423efa9a67Smalc     GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
10433efa9a67Smalc     GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
10443efa9a67Smalc     GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
10453efa9a67Smalc     GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
10463efa9a67Smalc     GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
10473efa9a67Smalc     GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
10483efa9a67Smalc     GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
10490e019746STom Musta     GET_FEATURE2(PPC2_DFP, QEMU_PPC_FEATURE_HAS_DFP);
10500e019746STom Musta     GET_FEATURE2(PPC2_VSX, QEMU_PPC_FEATURE_HAS_VSX);
10510e019746STom Musta     GET_FEATURE2((PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 |
10520e019746STom Musta                   PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206),
10530e019746STom Musta                   QEMU_PPC_FEATURE_ARCH_2_06);
1054df84e4f3SNathan Froyd #undef GET_FEATURE
10550e019746STom Musta #undef GET_FEATURE2
1056df84e4f3SNathan Froyd 
1057df84e4f3SNathan Froyd     return features;
1058df84e4f3SNathan Froyd }
1059df84e4f3SNathan Froyd 
1060a60438ddSTom Musta #define ELF_HWCAP2 get_elf_hwcap2()
1061a60438ddSTom Musta 
1062a60438ddSTom Musta static uint32_t get_elf_hwcap2(void)
1063a60438ddSTom Musta {
1064a60438ddSTom Musta     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
1065a60438ddSTom Musta     uint32_t features = 0;
1066a60438ddSTom Musta 
1067a60438ddSTom Musta #define GET_FEATURE(flag, feature)                                      \
1068a60438ddSTom Musta     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
1069a60438ddSTom Musta #define GET_FEATURE2(flag, feature)                                      \
1070a60438ddSTom Musta     do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
1071a60438ddSTom Musta 
1072a60438ddSTom Musta     GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL);
1073a60438ddSTom Musta     GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR);
1074a60438ddSTom Musta     GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
107524c373ecSLaurent Vivier                   PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07 |
107624c373ecSLaurent Vivier                   QEMU_PPC_FEATURE2_VEC_CRYPTO);
107724c373ecSLaurent Vivier     GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 |
10788a589aebSKhem Raj                  QEMU_PPC_FEATURE2_DARN | QEMU_PPC_FEATURE2_HAS_IEEE128);
107996c343ccSJoel Stanley     GET_FEATURE2(PPC2_ISA310, QEMU_PPC_FEATURE2_ARCH_3_1 |
108096c343ccSJoel Stanley                  QEMU_PPC_FEATURE2_MMA);
1081a60438ddSTom Musta 
1082a60438ddSTom Musta #undef GET_FEATURE
1083a60438ddSTom Musta #undef GET_FEATURE2
1084a60438ddSTom Musta 
1085a60438ddSTom Musta     return features;
1086a60438ddSTom Musta }
1087a60438ddSTom Musta 
1088f5155289Sbellard /*
1089f5155289Sbellard  * The requirements here are:
1090f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
1091f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
1092f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
1093f5155289Sbellard  *   AT_IGNOREPPC is used for that.
1094f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
1095f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
1096f5155289Sbellard  */
10970bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
1098f5155289Sbellard #define ARCH_DLINFO                                     \
1099f5155289Sbellard     do {                                                \
1100623e250aSTom Musta         PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);              \
1101f5155289Sbellard         /*                                              \
110282991bedSPeter Maydell          * Handle glibc compatibility: these magic entries must \
110382991bedSPeter Maydell          * be at the lowest addresses in the final auxv.        \
1104f5155289Sbellard          */                                             \
11050bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
11060bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
110782991bedSPeter Maydell         NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
110882991bedSPeter Maydell         NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
110982991bedSPeter Maydell         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                 \
1110f5155289Sbellard     } while (0)
1111f5155289Sbellard 
111267867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
111367867308Sbellard {
111467867308Sbellard     _regs->gpr[1] = infop->start_stack;
111574154d7eSThomas Huth #if defined(TARGET_PPC64)
1116d90b94cdSDoug Kwan     if (get_ppc64_abi(infop) < 2) {
11172ccf97ecSPeter Maydell         uint64_t val;
11182ccf97ecSPeter Maydell         get_user_u64(val, infop->entry + 8);
11192ccf97ecSPeter Maydell         _regs->gpr[2] = val + infop->load_bias;
11202ccf97ecSPeter Maydell         get_user_u64(val, infop->entry);
11212ccf97ecSPeter Maydell         infop->entry = val + infop->load_bias;
1122d90b94cdSDoug Kwan     } else {
1123d90b94cdSDoug Kwan         _regs->gpr[12] = infop->entry;  /* r12 set to global entry address */
1124d90b94cdSDoug Kwan     }
112584409ddbSj_mayer #endif
112667867308Sbellard     _regs->nip = infop->entry;
112767867308Sbellard }
112867867308Sbellard 
1129e2f3e741SNathan Froyd /* See linux kernel: arch/powerpc/include/asm/elf.h.  */
1130e2f3e741SNathan Froyd #define ELF_NREG 48
1131e2f3e741SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1132e2f3e741SNathan Froyd 
113305390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *env)
1134e2f3e741SNathan Froyd {
1135e2f3e741SNathan Froyd     int i;
1136e2f3e741SNathan Froyd     target_ulong ccr = 0;
1137e2f3e741SNathan Froyd 
1138e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
113986cd7b2dSPaolo Bonzini         (*regs)[i] = tswapreg(env->gpr[i]);
1140e2f3e741SNathan Froyd     }
1141e2f3e741SNathan Froyd 
114286cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->nip);
114386cd7b2dSPaolo Bonzini     (*regs)[33] = tswapreg(env->msr);
114486cd7b2dSPaolo Bonzini     (*regs)[35] = tswapreg(env->ctr);
114586cd7b2dSPaolo Bonzini     (*regs)[36] = tswapreg(env->lr);
114610de0521SMatheus Ferst     (*regs)[37] = tswapreg(cpu_read_xer(env));
1147e2f3e741SNathan Froyd 
11482060436aSHarsh Prateek Bora     ccr = ppc_get_cr(env);
114986cd7b2dSPaolo Bonzini     (*regs)[38] = tswapreg(ccr);
1150e2f3e741SNathan Froyd }
1151e2f3e741SNathan Froyd 
1152e2f3e741SNathan Froyd #define USE_ELF_CORE_DUMP
115367867308Sbellard #define ELF_EXEC_PAGESIZE       4096
115467867308Sbellard 
115567867308Sbellard #endif
115667867308Sbellard 
11573418fe25SSong Gao #ifdef TARGET_LOONGARCH64
11583418fe25SSong Gao 
11593418fe25SSong Gao #define ELF_CLASS   ELFCLASS64
11603418fe25SSong Gao #define ELF_ARCH    EM_LOONGARCH
1161872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
11623418fe25SSong Gao 
11633418fe25SSong Gao #define elf_check_arch(x) ((x) == EM_LOONGARCH)
11643418fe25SSong Gao 
11653418fe25SSong Gao static inline void init_thread(struct target_pt_regs *regs,
11663418fe25SSong Gao                                struct image_info *infop)
11673418fe25SSong Gao {
11683418fe25SSong Gao     /*Set crmd PG,DA = 1,0 */
11693418fe25SSong Gao     regs->csr.crmd = 2 << 3;
11703418fe25SSong Gao     regs->csr.era = infop->entry;
11713418fe25SSong Gao     regs->regs[3] = infop->start_stack;
11723418fe25SSong Gao }
11733418fe25SSong Gao 
11743418fe25SSong Gao /* See linux kernel: arch/loongarch/include/asm/elf.h */
11753418fe25SSong Gao #define ELF_NREG 45
11763418fe25SSong Gao typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
11773418fe25SSong Gao 
11783418fe25SSong Gao enum {
11793418fe25SSong Gao     TARGET_EF_R0 = 0,
11803418fe25SSong Gao     TARGET_EF_CSR_ERA = TARGET_EF_R0 + 33,
11813418fe25SSong Gao     TARGET_EF_CSR_BADV = TARGET_EF_R0 + 34,
11823418fe25SSong Gao };
11833418fe25SSong Gao 
11843418fe25SSong Gao static void elf_core_copy_regs(target_elf_gregset_t *regs,
11853418fe25SSong Gao                                const CPULoongArchState *env)
11863418fe25SSong Gao {
11873418fe25SSong Gao     int i;
11883418fe25SSong Gao 
11893418fe25SSong Gao     (*regs)[TARGET_EF_R0] = 0;
11903418fe25SSong Gao 
11913418fe25SSong Gao     for (i = 1; i < ARRAY_SIZE(env->gpr); i++) {
11923418fe25SSong Gao         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->gpr[i]);
11933418fe25SSong Gao     }
11943418fe25SSong Gao 
11953418fe25SSong Gao     (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->pc);
11963418fe25SSong Gao     (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV);
11973418fe25SSong Gao }
11983418fe25SSong Gao 
11993418fe25SSong Gao #define USE_ELF_CORE_DUMP
12003418fe25SSong Gao #define ELF_EXEC_PAGESIZE        4096
12013418fe25SSong Gao 
12023418fe25SSong Gao #define ELF_HWCAP get_elf_hwcap()
12033418fe25SSong Gao 
12043418fe25SSong Gao /* See arch/loongarch/include/uapi/asm/hwcap.h */
12053418fe25SSong Gao enum {
12063418fe25SSong Gao     HWCAP_LOONGARCH_CPUCFG   = (1 << 0),
12073418fe25SSong Gao     HWCAP_LOONGARCH_LAM      = (1 << 1),
12083418fe25SSong Gao     HWCAP_LOONGARCH_UAL      = (1 << 2),
12093418fe25SSong Gao     HWCAP_LOONGARCH_FPU      = (1 << 3),
12103418fe25SSong Gao     HWCAP_LOONGARCH_LSX      = (1 << 4),
12113418fe25SSong Gao     HWCAP_LOONGARCH_LASX     = (1 << 5),
12123418fe25SSong Gao     HWCAP_LOONGARCH_CRC32    = (1 << 6),
12133418fe25SSong Gao     HWCAP_LOONGARCH_COMPLEX  = (1 << 7),
12143418fe25SSong Gao     HWCAP_LOONGARCH_CRYPTO   = (1 << 8),
12153418fe25SSong Gao     HWCAP_LOONGARCH_LVZ      = (1 << 9),
12163418fe25SSong Gao     HWCAP_LOONGARCH_LBT_X86  = (1 << 10),
12173418fe25SSong Gao     HWCAP_LOONGARCH_LBT_ARM  = (1 << 11),
12183418fe25SSong Gao     HWCAP_LOONGARCH_LBT_MIPS = (1 << 12),
12193418fe25SSong Gao };
12203418fe25SSong Gao 
12213418fe25SSong Gao static uint32_t get_elf_hwcap(void)
12223418fe25SSong Gao {
12233418fe25SSong Gao     LoongArchCPU *cpu = LOONGARCH_CPU(thread_cpu);
12243418fe25SSong Gao     uint32_t hwcaps = 0;
12253418fe25SSong Gao 
12263418fe25SSong Gao     hwcaps |= HWCAP_LOONGARCH_CRC32;
12273418fe25SSong Gao 
12283418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[1], CPUCFG1, UAL)) {
12293418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_UAL;
12303418fe25SSong Gao     }
12313418fe25SSong Gao 
12323418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, FP)) {
12333418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_FPU;
12343418fe25SSong Gao     }
12353418fe25SSong Gao 
12363418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LAM)) {
12373418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_LAM;
12383418fe25SSong Gao     }
12393418fe25SSong Gao 
1240a9f6004fSJiajie Chen     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
1241a9f6004fSJiajie Chen         hwcaps |= HWCAP_LOONGARCH_LSX;
1242a9f6004fSJiajie Chen     }
1243a9f6004fSJiajie Chen 
1244a9f6004fSJiajie Chen     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) {
1245a9f6004fSJiajie Chen         hwcaps |= HWCAP_LOONGARCH_LASX;
1246a9f6004fSJiajie Chen     }
1247a9f6004fSJiajie Chen 
12483418fe25SSong Gao     return hwcaps;
12493418fe25SSong Gao }
12503418fe25SSong Gao 
12513418fe25SSong Gao #define ELF_PLATFORM "loongarch"
12523418fe25SSong Gao 
12533418fe25SSong Gao #endif /* TARGET_LOONGARCH64 */
12543418fe25SSong Gao 
1255048f6b4dSbellard #ifdef TARGET_MIPS
1256048f6b4dSbellard 
1257388bb21aSths #ifdef TARGET_MIPS64
1258388bb21aSths #define ELF_CLASS   ELFCLASS64
1259388bb21aSths #else
1260048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
1261388bb21aSths #endif
1262048f6b4dSbellard #define ELF_ARCH    EM_MIPS
1263872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
1264048f6b4dSbellard 
1265ace3d654SCarlo Marcelo Arenas Belón #ifdef TARGET_ABI_MIPSN32
1266ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) ((x) & EF_MIPS_ABI2)
1267ace3d654SCarlo Marcelo Arenas Belón #else
1268ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (!((x) & EF_MIPS_ABI2))
1269ace3d654SCarlo Marcelo Arenas Belón #endif
1270ace3d654SCarlo Marcelo Arenas Belón 
1271fbf47c18SJiaxun Yang #define ELF_BASE_PLATFORM get_elf_base_platform()
1272fbf47c18SJiaxun Yang 
1273fbf47c18SJiaxun Yang #define MATCH_PLATFORM_INSN(_flags, _base_platform)      \
1274fbf47c18SJiaxun Yang     do { if ((cpu->env.insn_flags & (_flags)) == _flags) \
1275fbf47c18SJiaxun Yang     { return _base_platform; } } while (0)
1276fbf47c18SJiaxun Yang 
1277fbf47c18SJiaxun Yang static const char *get_elf_base_platform(void)
1278fbf47c18SJiaxun Yang {
1279fbf47c18SJiaxun Yang     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
1280fbf47c18SJiaxun Yang 
1281fbf47c18SJiaxun Yang     /* 64 bit ISAs goes first */
1282fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R6, "mips64r6");
1283fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R5, "mips64r5");
1284fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R2, "mips64r2");
1285fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R1, "mips64");
1286fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS5, "mips5");
1287fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS4, "mips4");
1288fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS3, "mips3");
1289fbf47c18SJiaxun Yang 
1290fbf47c18SJiaxun Yang     /* 32 bit ISAs */
1291fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R6, "mips32r6");
1292fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R5, "mips32r5");
1293fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R2, "mips32r2");
1294fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R1, "mips32");
1295fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS2, "mips2");
1296fbf47c18SJiaxun Yang 
1297fbf47c18SJiaxun Yang     /* Fallback */
1298fbf47c18SJiaxun Yang     return "mips";
1299fbf47c18SJiaxun Yang }
1300fbf47c18SJiaxun Yang #undef MATCH_PLATFORM_INSN
1301fbf47c18SJiaxun Yang 
1302d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1303d97ef72eSRichard Henderson                                struct image_info *infop)
1304048f6b4dSbellard {
1305623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
1306048f6b4dSbellard     regs->cp0_epc = infop->entry;
1307048f6b4dSbellard     regs->regs[29] = infop->start_stack;
1308048f6b4dSbellard }
1309048f6b4dSbellard 
131051e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/elf.h.  */
131151e52606SNathan Froyd #define ELF_NREG 45
131251e52606SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
131351e52606SNathan Froyd 
131451e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/reg.h.  */
131551e52606SNathan Froyd enum {
131651e52606SNathan Froyd #ifdef TARGET_MIPS64
131751e52606SNathan Froyd     TARGET_EF_R0 = 0,
131851e52606SNathan Froyd #else
131951e52606SNathan Froyd     TARGET_EF_R0 = 6,
132051e52606SNathan Froyd #endif
132151e52606SNathan Froyd     TARGET_EF_R26 = TARGET_EF_R0 + 26,
132251e52606SNathan Froyd     TARGET_EF_R27 = TARGET_EF_R0 + 27,
132351e52606SNathan Froyd     TARGET_EF_LO = TARGET_EF_R0 + 32,
132451e52606SNathan Froyd     TARGET_EF_HI = TARGET_EF_R0 + 33,
132551e52606SNathan Froyd     TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
132651e52606SNathan Froyd     TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
132751e52606SNathan Froyd     TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
132851e52606SNathan Froyd     TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
132951e52606SNathan Froyd };
133051e52606SNathan Froyd 
133151e52606SNathan Froyd /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
133205390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMIPSState *env)
133351e52606SNathan Froyd {
133451e52606SNathan Froyd     int i;
133551e52606SNathan Froyd 
133651e52606SNathan Froyd     for (i = 0; i < TARGET_EF_R0; i++) {
133751e52606SNathan Froyd         (*regs)[i] = 0;
133851e52606SNathan Froyd     }
133951e52606SNathan Froyd     (*regs)[TARGET_EF_R0] = 0;
134051e52606SNathan Froyd 
134151e52606SNathan Froyd     for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
1342a29f998dSPaolo Bonzini         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]);
134351e52606SNathan Froyd     }
134451e52606SNathan Froyd 
134551e52606SNathan Froyd     (*regs)[TARGET_EF_R26] = 0;
134651e52606SNathan Froyd     (*regs)[TARGET_EF_R27] = 0;
1347a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_LO] = tswapreg(env->active_tc.LO[0]);
1348a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_HI] = tswapreg(env->active_tc.HI[0]);
1349a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_EPC] = tswapreg(env->active_tc.PC);
1350a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_BADVADDR] = tswapreg(env->CP0_BadVAddr);
1351a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_STATUS] = tswapreg(env->CP0_Status);
1352a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_CAUSE] = tswapreg(env->CP0_Cause);
135351e52606SNathan Froyd }
135451e52606SNathan Froyd 
135551e52606SNathan Froyd #define USE_ELF_CORE_DUMP
1356388bb21aSths #define ELF_EXEC_PAGESIZE        4096
1357388bb21aSths 
135846a1ee4fSJames Cowgill /* See arch/mips/include/uapi/asm/hwcap.h.  */
135946a1ee4fSJames Cowgill enum {
136046a1ee4fSJames Cowgill     HWCAP_MIPS_R6           = (1 << 0),
136146a1ee4fSJames Cowgill     HWCAP_MIPS_MSA          = (1 << 1),
13629ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_CRC32        = (1 << 2),
13639ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16       = (1 << 3),
13649ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MDMX         = (1 << 4),
13659ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS3D       = (1 << 5),
13669ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_SMARTMIPS    = (1 << 6),
13679ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP          = (1 << 7),
13689ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP2         = (1 << 8),
13699ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP3         = (1 << 9),
13709ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16E2     = (1 << 10),
13719ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_MMI      = (1 << 11),
13729ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT      = (1 << 12),
13739ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT2     = (1 << 13),
13749ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_CPUCFG   = (1 << 14),
137546a1ee4fSJames Cowgill };
137646a1ee4fSJames Cowgill 
137746a1ee4fSJames Cowgill #define ELF_HWCAP get_elf_hwcap()
137846a1ee4fSJames Cowgill 
13797d9a3d96SPhilippe Mathieu-Daudé #define GET_FEATURE_INSN(_flag, _hwcap) \
13806dd97bfcSPhilippe Mathieu-Daudé     do { if (cpu->env.insn_flags & (_flag)) { hwcaps |= _hwcap; } } while (0)
13816dd97bfcSPhilippe Mathieu-Daudé 
1382388765a0SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_SET(_reg, _mask, _hwcap) \
1383388765a0SPhilippe Mathieu-Daudé     do { if (cpu->env._reg & (_mask)) { hwcaps |= _hwcap; } } while (0)
1384388765a0SPhilippe Mathieu-Daudé 
1385ce543844SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_EQU(_reg, _start, _length, _val, _hwcap) \
1386ce543844SPhilippe Mathieu-Daudé     do { \
1387ce543844SPhilippe Mathieu-Daudé         if (extract32(cpu->env._reg, (_start), (_length)) == (_val)) { \
1388ce543844SPhilippe Mathieu-Daudé             hwcaps |= _hwcap; \
1389ce543844SPhilippe Mathieu-Daudé         } \
1390ce543844SPhilippe Mathieu-Daudé     } while (0)
1391ce543844SPhilippe Mathieu-Daudé 
139246a1ee4fSJames Cowgill static uint32_t get_elf_hwcap(void)
139346a1ee4fSJames Cowgill {
139446a1ee4fSJames Cowgill     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
139546a1ee4fSJames Cowgill     uint32_t hwcaps = 0;
139646a1ee4fSJames Cowgill 
1397ce543844SPhilippe Mathieu-Daudé     GET_FEATURE_REG_EQU(CP0_Config0, CP0C0_AR, CP0C0_AR_LENGTH,
1398ce543844SPhilippe Mathieu-Daudé                         2, HWCAP_MIPS_R6);
1399388765a0SPhilippe Mathieu-Daudé     GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA);
140053673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LMMI, HWCAP_LOONGSON_MMI);
140153673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LEXT, HWCAP_LOONGSON_EXT);
140246a1ee4fSJames Cowgill 
140346a1ee4fSJames Cowgill     return hwcaps;
140446a1ee4fSJames Cowgill }
140546a1ee4fSJames Cowgill 
1406ce543844SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_EQU
1407388765a0SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_SET
14087d9a3d96SPhilippe Mathieu-Daudé #undef GET_FEATURE_INSN
14096dd97bfcSPhilippe Mathieu-Daudé 
1410048f6b4dSbellard #endif /* TARGET_MIPS */
1411048f6b4dSbellard 
1412b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
1413b779e29eSEdgar E. Iglesias 
14140d5d4699SEdgar E. Iglesias #define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
1415b779e29eSEdgar E. Iglesias 
1416b779e29eSEdgar E. Iglesias #define ELF_CLASS   ELFCLASS32
14170d5d4699SEdgar E. Iglesias #define ELF_ARCH    EM_MICROBLAZE
1418b779e29eSEdgar E. Iglesias 
1419d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1420d97ef72eSRichard Henderson                                struct image_info *infop)
1421b779e29eSEdgar E. Iglesias {
1422b779e29eSEdgar E. Iglesias     regs->pc = infop->entry;
1423b779e29eSEdgar E. Iglesias     regs->r1 = infop->start_stack;
1424b779e29eSEdgar E. Iglesias 
1425b779e29eSEdgar E. Iglesias }
1426b779e29eSEdgar E. Iglesias 
1427b779e29eSEdgar E. Iglesias #define ELF_EXEC_PAGESIZE        4096
1428b779e29eSEdgar E. Iglesias 
1429e4cbd44dSEdgar E. Iglesias #define USE_ELF_CORE_DUMP
1430e4cbd44dSEdgar E. Iglesias #define ELF_NREG 38
1431e4cbd44dSEdgar E. Iglesias typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1432e4cbd44dSEdgar E. Iglesias 
1433e4cbd44dSEdgar E. Iglesias /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
143405390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env)
1435e4cbd44dSEdgar E. Iglesias {
1436e4cbd44dSEdgar E. Iglesias     int i, pos = 0;
1437e4cbd44dSEdgar E. Iglesias 
1438e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 32; i++) {
143986cd7b2dSPaolo Bonzini         (*regs)[pos++] = tswapreg(env->regs[i]);
1440e4cbd44dSEdgar E. Iglesias     }
1441e4cbd44dSEdgar E. Iglesias 
1442af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->pc);
14431074c0fbSRichard Henderson     (*regs)[pos++] = tswapreg(mb_cpu_read_msr(env));
1444af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1445af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->ear);
1446af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1447af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->esr);
1448e4cbd44dSEdgar E. Iglesias }
1449e4cbd44dSEdgar E. Iglesias 
1450b779e29eSEdgar E. Iglesias #endif /* TARGET_MICROBLAZE */
1451b779e29eSEdgar E. Iglesias 
1452a0a839b6SMarek Vasut #ifdef TARGET_NIOS2
1453a0a839b6SMarek Vasut 
1454a0a839b6SMarek Vasut #define elf_check_arch(x) ((x) == EM_ALTERA_NIOS2)
1455a0a839b6SMarek Vasut 
1456a0a839b6SMarek Vasut #define ELF_CLASS   ELFCLASS32
1457a0a839b6SMarek Vasut #define ELF_ARCH    EM_ALTERA_NIOS2
1458a0a839b6SMarek Vasut 
1459a0a839b6SMarek Vasut static void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1460a0a839b6SMarek Vasut {
1461a0a839b6SMarek Vasut     regs->ea = infop->entry;
1462a0a839b6SMarek Vasut     regs->sp = infop->start_stack;
1463a0a839b6SMarek Vasut }
1464a0a839b6SMarek Vasut 
1465f5ef0e51SRichard Henderson #define LO_COMMPAGE  TARGET_PAGE_SIZE
1466f5ef0e51SRichard Henderson 
1467f5ef0e51SRichard Henderson static bool init_guest_commpage(void)
1468f5ef0e51SRichard Henderson {
1469f5ef0e51SRichard Henderson     static const uint8_t kuser_page[4 + 2 * 64] = {
1470f5ef0e51SRichard Henderson         /* __kuser_helper_version */
1471f5ef0e51SRichard Henderson         [0x00] = 0x02, 0x00, 0x00, 0x00,
1472f5ef0e51SRichard Henderson 
1473f5ef0e51SRichard Henderson         /* __kuser_cmpxchg */
1474f5ef0e51SRichard Henderson         [0x04] = 0x3a, 0x6c, 0x3b, 0x00,  /* trap 16 */
1475f5ef0e51SRichard Henderson                  0x3a, 0x28, 0x00, 0xf8,  /* ret */
1476f5ef0e51SRichard Henderson 
1477f5ef0e51SRichard Henderson         /* __kuser_sigtramp */
1478f5ef0e51SRichard Henderson         [0x44] = 0xc4, 0x22, 0x80, 0x00,  /* movi r2, __NR_rt_sigreturn */
1479f5ef0e51SRichard Henderson                  0x3a, 0x68, 0x3b, 0x00,  /* trap 0 */
1480f5ef0e51SRichard Henderson     };
1481f5ef0e51SRichard Henderson 
1482f5ef0e51SRichard Henderson     void *want = g2h_untagged(LO_COMMPAGE & -qemu_host_page_size);
1483f5ef0e51SRichard Henderson     void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
1484f5ef0e51SRichard Henderson                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1485f5ef0e51SRichard Henderson 
1486f5ef0e51SRichard Henderson     if (addr == MAP_FAILED) {
1487f5ef0e51SRichard Henderson         perror("Allocating guest commpage");
1488f5ef0e51SRichard Henderson         exit(EXIT_FAILURE);
1489f5ef0e51SRichard Henderson     }
1490f5ef0e51SRichard Henderson     if (addr != want) {
1491f5ef0e51SRichard Henderson         return false;
1492f5ef0e51SRichard Henderson     }
1493f5ef0e51SRichard Henderson 
1494f5ef0e51SRichard Henderson     memcpy(addr, kuser_page, sizeof(kuser_page));
1495f5ef0e51SRichard Henderson 
1496f5ef0e51SRichard Henderson     if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
1497f5ef0e51SRichard Henderson         perror("Protecting guest commpage");
1498f5ef0e51SRichard Henderson         exit(EXIT_FAILURE);
1499f5ef0e51SRichard Henderson     }
1500f5ef0e51SRichard Henderson 
150149840a4aSRichard Henderson     page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
1502f5ef0e51SRichard Henderson                    PAGE_READ | PAGE_EXEC | PAGE_VALID);
1503f5ef0e51SRichard Henderson     return true;
1504f5ef0e51SRichard Henderson }
1505f5ef0e51SRichard Henderson 
1506a0a839b6SMarek Vasut #define ELF_EXEC_PAGESIZE        4096
1507a0a839b6SMarek Vasut 
1508a0a839b6SMarek Vasut #define USE_ELF_CORE_DUMP
1509a0a839b6SMarek Vasut #define ELF_NREG 49
1510a0a839b6SMarek Vasut typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1511a0a839b6SMarek Vasut 
1512a0a839b6SMarek Vasut /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
1513a0a839b6SMarek Vasut static void elf_core_copy_regs(target_elf_gregset_t *regs,
1514a0a839b6SMarek Vasut                                const CPUNios2State *env)
1515a0a839b6SMarek Vasut {
1516a0a839b6SMarek Vasut     int i;
1517a0a839b6SMarek Vasut 
1518a0a839b6SMarek Vasut     (*regs)[0] = -1;
1519a0a839b6SMarek Vasut     for (i = 1; i < 8; i++)    /* r0-r7 */
1520a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1521a0a839b6SMarek Vasut 
1522a0a839b6SMarek Vasut     for (i = 8; i < 16; i++)   /* r8-r15 */
1523a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i - 8]);
1524a0a839b6SMarek Vasut 
1525a0a839b6SMarek Vasut     for (i = 16; i < 24; i++)  /* r16-r23 */
1526a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1527a0a839b6SMarek Vasut     (*regs)[24] = -1;    /* R_ET */
1528a0a839b6SMarek Vasut     (*regs)[25] = -1;    /* R_BT */
1529a0a839b6SMarek Vasut     (*regs)[26] = tswapreg(env->regs[R_GP]);
1530a0a839b6SMarek Vasut     (*regs)[27] = tswapreg(env->regs[R_SP]);
1531a0a839b6SMarek Vasut     (*regs)[28] = tswapreg(env->regs[R_FP]);
1532a0a839b6SMarek Vasut     (*regs)[29] = tswapreg(env->regs[R_EA]);
1533a0a839b6SMarek Vasut     (*regs)[30] = -1;    /* R_SSTATUS */
1534a0a839b6SMarek Vasut     (*regs)[31] = tswapreg(env->regs[R_RA]);
1535a0a839b6SMarek Vasut 
153617a406eeSRichard Henderson     (*regs)[32] = tswapreg(env->pc);
1537a0a839b6SMarek Vasut 
1538a0a839b6SMarek Vasut     (*regs)[33] = -1; /* R_STATUS */
1539a0a839b6SMarek Vasut     (*regs)[34] = tswapreg(env->regs[CR_ESTATUS]);
1540a0a839b6SMarek Vasut 
1541a0a839b6SMarek Vasut     for (i = 35; i < 49; i++)    /* ... */
1542a0a839b6SMarek Vasut         (*regs)[i] = -1;
1543a0a839b6SMarek Vasut }
1544a0a839b6SMarek Vasut 
1545a0a839b6SMarek Vasut #endif /* TARGET_NIOS2 */
1546a0a839b6SMarek Vasut 
1547d962783eSJia Liu #ifdef TARGET_OPENRISC
1548d962783eSJia Liu 
1549d962783eSJia Liu #define ELF_ARCH EM_OPENRISC
1550d962783eSJia Liu #define ELF_CLASS ELFCLASS32
1551d962783eSJia Liu #define ELF_DATA  ELFDATA2MSB
1552d962783eSJia Liu 
1553d962783eSJia Liu static inline void init_thread(struct target_pt_regs *regs,
1554d962783eSJia Liu                                struct image_info *infop)
1555d962783eSJia Liu {
1556d962783eSJia Liu     regs->pc = infop->entry;
1557d962783eSJia Liu     regs->gpr[1] = infop->start_stack;
1558d962783eSJia Liu }
1559d962783eSJia Liu 
1560d962783eSJia Liu #define USE_ELF_CORE_DUMP
1561d962783eSJia Liu #define ELF_EXEC_PAGESIZE 8192
1562d962783eSJia Liu 
1563d962783eSJia Liu /* See linux kernel arch/openrisc/include/asm/elf.h.  */
1564d962783eSJia Liu #define ELF_NREG 34 /* gprs and pc, sr */
1565d962783eSJia Liu typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1566d962783eSJia Liu 
1567d962783eSJia Liu static void elf_core_copy_regs(target_elf_gregset_t *regs,
1568d962783eSJia Liu                                const CPUOpenRISCState *env)
1569d962783eSJia Liu {
1570d962783eSJia Liu     int i;
1571d962783eSJia Liu 
1572d962783eSJia Liu     for (i = 0; i < 32; i++) {
1573d89e71e8SStafford Horne         (*regs)[i] = tswapreg(cpu_get_gpr(env, i));
1574d962783eSJia Liu     }
157586cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->pc);
157684775c43SRichard Henderson     (*regs)[33] = tswapreg(cpu_get_sr(env));
1577d962783eSJia Liu }
1578d962783eSJia Liu #define ELF_HWCAP 0
1579d962783eSJia Liu #define ELF_PLATFORM NULL
1580d962783eSJia Liu 
1581d962783eSJia Liu #endif /* TARGET_OPENRISC */
1582d962783eSJia Liu 
1583fdf9b3e8Sbellard #ifdef TARGET_SH4
1584fdf9b3e8Sbellard 
1585fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
1586fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
1587fdf9b3e8Sbellard 
1588d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1589d97ef72eSRichard Henderson                                struct image_info *infop)
1590fdf9b3e8Sbellard {
1591fdf9b3e8Sbellard     /* Check other registers XXXXX */
1592fdf9b3e8Sbellard     regs->pc = infop->entry;
1593072ae847Sths     regs->regs[15] = infop->start_stack;
1594fdf9b3e8Sbellard }
1595fdf9b3e8Sbellard 
15967631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/elf.h.  */
15977631c97eSNathan Froyd #define ELF_NREG 23
15987631c97eSNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
15997631c97eSNathan Froyd 
16007631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/ptrace.h.  */
16017631c97eSNathan Froyd enum {
16027631c97eSNathan Froyd     TARGET_REG_PC = 16,
16037631c97eSNathan Froyd     TARGET_REG_PR = 17,
16047631c97eSNathan Froyd     TARGET_REG_SR = 18,
16057631c97eSNathan Froyd     TARGET_REG_GBR = 19,
16067631c97eSNathan Froyd     TARGET_REG_MACH = 20,
16077631c97eSNathan Froyd     TARGET_REG_MACL = 21,
16087631c97eSNathan Froyd     TARGET_REG_SYSCALL = 22
16097631c97eSNathan Froyd };
16107631c97eSNathan Froyd 
1611d97ef72eSRichard Henderson static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
161205390248SAndreas Färber                                       const CPUSH4State *env)
16137631c97eSNathan Froyd {
16147631c97eSNathan Froyd     int i;
16157631c97eSNathan Froyd 
16167631c97eSNathan Froyd     for (i = 0; i < 16; i++) {
161772cd500bSPhilippe Mathieu-Daudé         (*regs)[i] = tswapreg(env->gregs[i]);
16187631c97eSNathan Froyd     }
16197631c97eSNathan Froyd 
162086cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
162186cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PR] = tswapreg(env->pr);
162286cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_SR] = tswapreg(env->sr);
162386cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_GBR] = tswapreg(env->gbr);
162486cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACH] = tswapreg(env->mach);
162586cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACL] = tswapreg(env->macl);
16267631c97eSNathan Froyd     (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
16277631c97eSNathan Froyd }
16287631c97eSNathan Froyd 
16297631c97eSNathan Froyd #define USE_ELF_CORE_DUMP
1630fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
1631fdf9b3e8Sbellard 
1632e42fd944SRichard Henderson enum {
1633e42fd944SRichard Henderson     SH_CPU_HAS_FPU            = 0x0001, /* Hardware FPU support */
1634e42fd944SRichard Henderson     SH_CPU_HAS_P2_FLUSH_BUG   = 0x0002, /* Need to flush the cache in P2 area */
1635e42fd944SRichard Henderson     SH_CPU_HAS_MMU_PAGE_ASSOC = 0x0004, /* SH3: TLB way selection bit support */
1636e42fd944SRichard Henderson     SH_CPU_HAS_DSP            = 0x0008, /* SH-DSP: DSP support */
1637e42fd944SRichard Henderson     SH_CPU_HAS_PERF_COUNTER   = 0x0010, /* Hardware performance counters */
1638e42fd944SRichard Henderson     SH_CPU_HAS_PTEA           = 0x0020, /* PTEA register */
1639e42fd944SRichard Henderson     SH_CPU_HAS_LLSC           = 0x0040, /* movli.l/movco.l */
1640e42fd944SRichard Henderson     SH_CPU_HAS_L2_CACHE       = 0x0080, /* Secondary cache / URAM */
1641e42fd944SRichard Henderson     SH_CPU_HAS_OP32           = 0x0100, /* 32-bit instruction support */
1642e42fd944SRichard Henderson     SH_CPU_HAS_PTEAEX         = 0x0200, /* PTE ASID Extension support */
1643e42fd944SRichard Henderson };
1644e42fd944SRichard Henderson 
1645e42fd944SRichard Henderson #define ELF_HWCAP get_elf_hwcap()
1646e42fd944SRichard Henderson 
1647e42fd944SRichard Henderson static uint32_t get_elf_hwcap(void)
1648e42fd944SRichard Henderson {
1649e42fd944SRichard Henderson     SuperHCPU *cpu = SUPERH_CPU(thread_cpu);
1650e42fd944SRichard Henderson     uint32_t hwcap = 0;
1651e42fd944SRichard Henderson 
1652e42fd944SRichard Henderson     hwcap |= SH_CPU_HAS_FPU;
1653e42fd944SRichard Henderson 
1654e42fd944SRichard Henderson     if (cpu->env.features & SH_FEATURE_SH4A) {
1655e42fd944SRichard Henderson         hwcap |= SH_CPU_HAS_LLSC;
1656e42fd944SRichard Henderson     }
1657e42fd944SRichard Henderson 
1658e42fd944SRichard Henderson     return hwcap;
1659e42fd944SRichard Henderson }
1660e42fd944SRichard Henderson 
1661fdf9b3e8Sbellard #endif
1662fdf9b3e8Sbellard 
166348733d19Sths #ifdef TARGET_CRIS
166448733d19Sths 
166548733d19Sths #define ELF_CLASS ELFCLASS32
166648733d19Sths #define ELF_ARCH  EM_CRIS
166748733d19Sths 
1668d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1669d97ef72eSRichard Henderson                                struct image_info *infop)
167048733d19Sths {
167148733d19Sths     regs->erp = infop->entry;
167248733d19Sths }
167348733d19Sths 
167448733d19Sths #define ELF_EXEC_PAGESIZE        8192
167548733d19Sths 
167648733d19Sths #endif
167748733d19Sths 
1678e6e5906bSpbrook #ifdef TARGET_M68K
1679e6e5906bSpbrook 
1680e6e5906bSpbrook #define ELF_CLASS       ELFCLASS32
1681e6e5906bSpbrook #define ELF_ARCH        EM_68K
1682e6e5906bSpbrook 
1683e6e5906bSpbrook /* ??? Does this need to do anything?
1684e6e5906bSpbrook    #define ELF_PLAT_INIT(_r) */
1685e6e5906bSpbrook 
1686d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1687d97ef72eSRichard Henderson                                struct image_info *infop)
1688e6e5906bSpbrook {
1689e6e5906bSpbrook     regs->usp = infop->start_stack;
1690e6e5906bSpbrook     regs->sr = 0;
1691e6e5906bSpbrook     regs->pc = infop->entry;
1692e6e5906bSpbrook }
1693e6e5906bSpbrook 
16947a93cc55SNathan Froyd /* See linux kernel: arch/m68k/include/asm/elf.h.  */
16957a93cc55SNathan Froyd #define ELF_NREG 20
16967a93cc55SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
16977a93cc55SNathan Froyd 
169805390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUM68KState *env)
16997a93cc55SNathan Froyd {
170086cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->dregs[1]);
170186cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->dregs[2]);
170286cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->dregs[3]);
170386cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->dregs[4]);
170486cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->dregs[5]);
170586cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->dregs[6]);
170686cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->dregs[7]);
170786cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->aregs[0]);
170886cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->aregs[1]);
170986cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->aregs[2]);
171086cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->aregs[3]);
171186cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->aregs[4]);
171286cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->aregs[5]);
171386cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->aregs[6]);
171486cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->dregs[0]);
171586cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->aregs[7]);
171686cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(env->dregs[0]); /* FIXME: orig_d0 */
171786cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->sr);
171886cd7b2dSPaolo Bonzini     (*regs)[18] = tswapreg(env->pc);
17197a93cc55SNathan Froyd     (*regs)[19] = 0;  /* FIXME: regs->format | regs->vector */
17207a93cc55SNathan Froyd }
17217a93cc55SNathan Froyd 
17227a93cc55SNathan Froyd #define USE_ELF_CORE_DUMP
1723e6e5906bSpbrook #define ELF_EXEC_PAGESIZE       8192
1724e6e5906bSpbrook 
1725e6e5906bSpbrook #endif
1726e6e5906bSpbrook 
17277a3148a9Sj_mayer #ifdef TARGET_ALPHA
17287a3148a9Sj_mayer 
17297a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
17307a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
17317a3148a9Sj_mayer 
1732d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1733d97ef72eSRichard Henderson                                struct image_info *infop)
17347a3148a9Sj_mayer {
17357a3148a9Sj_mayer     regs->pc = infop->entry;
17367a3148a9Sj_mayer     regs->ps = 8;
17377a3148a9Sj_mayer     regs->usp = infop->start_stack;
17387a3148a9Sj_mayer }
17397a3148a9Sj_mayer 
17407a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
17417a3148a9Sj_mayer 
17427a3148a9Sj_mayer #endif /* TARGET_ALPHA */
17437a3148a9Sj_mayer 
1744a4c075f1SUlrich Hecht #ifdef TARGET_S390X
1745a4c075f1SUlrich Hecht 
1746a4c075f1SUlrich Hecht #define ELF_CLASS	ELFCLASS64
1747a4c075f1SUlrich Hecht #define ELF_DATA	ELFDATA2MSB
1748a4c075f1SUlrich Hecht #define ELF_ARCH	EM_S390
1749a4c075f1SUlrich Hecht 
17506d88baf1SDavid Hildenbrand #include "elf.h"
17516d88baf1SDavid Hildenbrand 
17526d88baf1SDavid Hildenbrand #define ELF_HWCAP get_elf_hwcap()
17536d88baf1SDavid Hildenbrand 
17546d88baf1SDavid Hildenbrand #define GET_FEATURE(_feat, _hwcap) \
17556d88baf1SDavid Hildenbrand     do { if (s390_has_feat(_feat)) { hwcap |= _hwcap; } } while (0)
17566d88baf1SDavid Hildenbrand 
1757e1b819c8SIlya Leoshkevich uint32_t get_elf_hwcap(void)
17586d88baf1SDavid Hildenbrand {
17596d88baf1SDavid Hildenbrand     /*
17606d88baf1SDavid Hildenbrand      * Let's assume we always have esan3 and zarch.
17616d88baf1SDavid Hildenbrand      * 31-bit processes can use 64-bit registers (high gprs).
17626d88baf1SDavid Hildenbrand      */
17636d88baf1SDavid Hildenbrand     uint32_t hwcap = HWCAP_S390_ESAN3 | HWCAP_S390_ZARCH | HWCAP_S390_HIGH_GPRS;
17646d88baf1SDavid Hildenbrand 
17656d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_STFLE, HWCAP_S390_STFLE);
17666d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_MSA, HWCAP_S390_MSA);
17676d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_LONG_DISPLACEMENT, HWCAP_S390_LDISP);
17686d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_EXTENDED_IMMEDIATE, HWCAP_S390_EIMM);
17696d88baf1SDavid Hildenbrand     if (s390_has_feat(S390_FEAT_EXTENDED_TRANSLATION_3) &&
17706d88baf1SDavid Hildenbrand         s390_has_feat(S390_FEAT_ETF3_ENH)) {
17716d88baf1SDavid Hildenbrand         hwcap |= HWCAP_S390_ETF3EH;
17726d88baf1SDavid Hildenbrand     }
17736d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS);
1774da215c23SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR_ENH, HWCAP_S390_VXRS_EXT);
1775ffc8453bSIlya Leoshkevich     GET_FEATURE(S390_FEAT_VECTOR_ENH2, HWCAP_S390_VXRS_EXT2);
17766d88baf1SDavid Hildenbrand 
17776d88baf1SDavid Hildenbrand     return hwcap;
17786d88baf1SDavid Hildenbrand }
17796d88baf1SDavid Hildenbrand 
1780e19807beSIlya Leoshkevich const char *elf_hwcap_str(uint32_t bit)
1781e19807beSIlya Leoshkevich {
1782e19807beSIlya Leoshkevich     static const char *hwcap_str[] = {
17837f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ESAN3]     = "esan3",
17847f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ZARCH]     = "zarch",
17857f114a58SIlya Leoshkevich         [HWCAP_S390_NR_STFLE]     = "stfle",
17867f114a58SIlya Leoshkevich         [HWCAP_S390_NR_MSA]       = "msa",
17877f114a58SIlya Leoshkevich         [HWCAP_S390_NR_LDISP]     = "ldisp",
17887f114a58SIlya Leoshkevich         [HWCAP_S390_NR_EIMM]      = "eimm",
17897f114a58SIlya Leoshkevich         [HWCAP_S390_NR_DFP]       = "dfp",
17907f114a58SIlya Leoshkevich         [HWCAP_S390_NR_HPAGE]     = "edat",
17917f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ETF3EH]    = "etf3eh",
17927f114a58SIlya Leoshkevich         [HWCAP_S390_NR_HIGH_GPRS] = "highgprs",
17937f114a58SIlya Leoshkevich         [HWCAP_S390_NR_TE]        = "te",
17947f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS]      = "vx",
17957f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_BCD]  = "vxd",
17967f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_EXT]  = "vxe",
17977f114a58SIlya Leoshkevich         [HWCAP_S390_NR_GS]        = "gs",
17987f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_EXT2] = "vxe2",
17997f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_PDE]  = "vxp",
18007f114a58SIlya Leoshkevich         [HWCAP_S390_NR_SORT]      = "sort",
18017f114a58SIlya Leoshkevich         [HWCAP_S390_NR_DFLT]      = "dflt",
18027f114a58SIlya Leoshkevich         [HWCAP_S390_NR_NNPA]      = "nnpa",
18037f114a58SIlya Leoshkevich         [HWCAP_S390_NR_PCI_MIO]   = "pcimio",
18047f114a58SIlya Leoshkevich         [HWCAP_S390_NR_SIE]       = "sie",
1805e19807beSIlya Leoshkevich     };
1806e19807beSIlya Leoshkevich 
1807e19807beSIlya Leoshkevich     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
1808e19807beSIlya Leoshkevich }
1809e19807beSIlya Leoshkevich 
1810a4c075f1SUlrich Hecht static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1811a4c075f1SUlrich Hecht {
1812a4c075f1SUlrich Hecht     regs->psw.addr = infop->entry;
181378a1e153SIlya Leoshkevich     regs->psw.mask = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | \
181478a1e153SIlya Leoshkevich                      PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_MASK_64 | \
181578a1e153SIlya Leoshkevich                      PSW_MASK_32;
1816a4c075f1SUlrich Hecht     regs->gprs[15] = infop->start_stack;
1817a4c075f1SUlrich Hecht }
1818a4c075f1SUlrich Hecht 
18194a1e8931SIlya Leoshkevich /* See linux kernel: arch/s390/include/uapi/asm/ptrace.h (s390_regs).  */
18204a1e8931SIlya Leoshkevich #define ELF_NREG 27
18214a1e8931SIlya Leoshkevich typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
18224a1e8931SIlya Leoshkevich 
18234a1e8931SIlya Leoshkevich enum {
18244a1e8931SIlya Leoshkevich     TARGET_REG_PSWM = 0,
18254a1e8931SIlya Leoshkevich     TARGET_REG_PSWA = 1,
18264a1e8931SIlya Leoshkevich     TARGET_REG_GPRS = 2,
18274a1e8931SIlya Leoshkevich     TARGET_REG_ARS = 18,
18284a1e8931SIlya Leoshkevich     TARGET_REG_ORIG_R2 = 26,
18294a1e8931SIlya Leoshkevich };
18304a1e8931SIlya Leoshkevich 
18314a1e8931SIlya Leoshkevich static void elf_core_copy_regs(target_elf_gregset_t *regs,
18324a1e8931SIlya Leoshkevich                                const CPUS390XState *env)
18334a1e8931SIlya Leoshkevich {
18344a1e8931SIlya Leoshkevich     int i;
18354a1e8931SIlya Leoshkevich     uint32_t *aregs;
18364a1e8931SIlya Leoshkevich 
18374a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWM] = tswapreg(env->psw.mask);
18384a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWA] = tswapreg(env->psw.addr);
18394a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
18404a1e8931SIlya Leoshkevich         (*regs)[TARGET_REG_GPRS + i] = tswapreg(env->regs[i]);
18414a1e8931SIlya Leoshkevich     }
18424a1e8931SIlya Leoshkevich     aregs = (uint32_t *)&((*regs)[TARGET_REG_ARS]);
18434a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
18444a1e8931SIlya Leoshkevich         aregs[i] = tswap32(env->aregs[i]);
18454a1e8931SIlya Leoshkevich     }
18464a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_ORIG_R2] = 0;
18474a1e8931SIlya Leoshkevich }
18484a1e8931SIlya Leoshkevich 
18494a1e8931SIlya Leoshkevich #define USE_ELF_CORE_DUMP
18504a1e8931SIlya Leoshkevich #define ELF_EXEC_PAGESIZE 4096
18514a1e8931SIlya Leoshkevich 
1852a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
1853a4c075f1SUlrich Hecht 
185447ae93cdSMichael Clark #ifdef TARGET_RISCV
185547ae93cdSMichael Clark 
185647ae93cdSMichael Clark #define ELF_ARCH  EM_RISCV
185747ae93cdSMichael Clark 
185847ae93cdSMichael Clark #ifdef TARGET_RISCV32
185947ae93cdSMichael Clark #define ELF_CLASS ELFCLASS32
186047ae93cdSMichael Clark #else
186147ae93cdSMichael Clark #define ELF_CLASS ELFCLASS64
186247ae93cdSMichael Clark #endif
186347ae93cdSMichael Clark 
1864cb46938cSKito Cheng #define ELF_HWCAP get_elf_hwcap()
1865cb46938cSKito Cheng 
1866cb46938cSKito Cheng static uint32_t get_elf_hwcap(void)
1867cb46938cSKito Cheng {
1868cb46938cSKito Cheng #define MISA_BIT(EXT) (1 << (EXT - 'A'))
1869cb46938cSKito Cheng     RISCVCPU *cpu = RISCV_CPU(thread_cpu);
1870cb46938cSKito Cheng     uint32_t mask = MISA_BIT('I') | MISA_BIT('M') | MISA_BIT('A')
18714333f092SNathan Egge                     | MISA_BIT('F') | MISA_BIT('D') | MISA_BIT('C')
18724333f092SNathan Egge                     | MISA_BIT('V');
1873cb46938cSKito Cheng 
1874e91a7227SRichard Henderson     return cpu->env.misa_ext & mask;
1875cb46938cSKito Cheng #undef MISA_BIT
1876cb46938cSKito Cheng }
1877cb46938cSKito Cheng 
187847ae93cdSMichael Clark static inline void init_thread(struct target_pt_regs *regs,
187947ae93cdSMichael Clark                                struct image_info *infop)
188047ae93cdSMichael Clark {
188147ae93cdSMichael Clark     regs->sepc = infop->entry;
188247ae93cdSMichael Clark     regs->sp = infop->start_stack;
188347ae93cdSMichael Clark }
188447ae93cdSMichael Clark 
188547ae93cdSMichael Clark #define ELF_EXEC_PAGESIZE 4096
188647ae93cdSMichael Clark 
188747ae93cdSMichael Clark #endif /* TARGET_RISCV */
188847ae93cdSMichael Clark 
18897c248bcdSRichard Henderson #ifdef TARGET_HPPA
18907c248bcdSRichard Henderson 
18917c248bcdSRichard Henderson #define ELF_CLASS       ELFCLASS32
18927c248bcdSRichard Henderson #define ELF_ARCH        EM_PARISC
18937c248bcdSRichard Henderson #define ELF_PLATFORM    "PARISC"
18947c248bcdSRichard Henderson #define STACK_GROWS_DOWN 0
18957c248bcdSRichard Henderson #define STACK_ALIGNMENT  64
18967c248bcdSRichard Henderson 
18977c248bcdSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
18987c248bcdSRichard Henderson                                struct image_info *infop)
18997c248bcdSRichard Henderson {
19007c248bcdSRichard Henderson     regs->iaoq[0] = infop->entry;
19017c248bcdSRichard Henderson     regs->iaoq[1] = infop->entry + 4;
19027c248bcdSRichard Henderson     regs->gr[23] = 0;
190360f1c801SRichard Henderson     regs->gr[24] = infop->argv;
190460f1c801SRichard Henderson     regs->gr[25] = infop->argc;
19057c248bcdSRichard Henderson     /* The top-of-stack contains a linkage buffer.  */
19067c248bcdSRichard Henderson     regs->gr[30] = infop->start_stack + 64;
19077c248bcdSRichard Henderson     regs->gr[31] = infop->entry;
19087c248bcdSRichard Henderson }
19097c248bcdSRichard Henderson 
1910eee816c0SRichard Henderson #define LO_COMMPAGE  0
1911eee816c0SRichard Henderson 
1912eee816c0SRichard Henderson static bool init_guest_commpage(void)
1913eee816c0SRichard Henderson {
1914eee816c0SRichard Henderson     void *want = g2h_untagged(LO_COMMPAGE);
1915eee816c0SRichard Henderson     void *addr = mmap(want, qemu_host_page_size, PROT_NONE,
1916eee816c0SRichard Henderson                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1917eee816c0SRichard Henderson 
1918eee816c0SRichard Henderson     if (addr == MAP_FAILED) {
1919eee816c0SRichard Henderson         perror("Allocating guest commpage");
1920eee816c0SRichard Henderson         exit(EXIT_FAILURE);
1921eee816c0SRichard Henderson     }
1922eee816c0SRichard Henderson     if (addr != want) {
1923eee816c0SRichard Henderson         return false;
1924eee816c0SRichard Henderson     }
1925eee816c0SRichard Henderson 
1926eee816c0SRichard Henderson     /*
1927eee816c0SRichard Henderson      * On Linux, page zero is normally marked execute only + gateway.
1928eee816c0SRichard Henderson      * Normal read or write is supposed to fail (thus PROT_NONE above),
1929eee816c0SRichard Henderson      * but specific offsets have kernel code mapped to raise permissions
1930eee816c0SRichard Henderson      * and implement syscalls.  Here, simply mark the page executable.
1931eee816c0SRichard Henderson      * Special case the entry points during translation (see do_page_zero).
1932eee816c0SRichard Henderson      */
193349840a4aSRichard Henderson     page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
1934eee816c0SRichard Henderson                    PAGE_EXEC | PAGE_VALID);
1935eee816c0SRichard Henderson     return true;
1936eee816c0SRichard Henderson }
1937eee816c0SRichard Henderson 
19387c248bcdSRichard Henderson #endif /* TARGET_HPPA */
19397c248bcdSRichard Henderson 
1940ba7651fbSMax Filippov #ifdef TARGET_XTENSA
1941ba7651fbSMax Filippov 
1942ba7651fbSMax Filippov #define ELF_CLASS       ELFCLASS32
1943ba7651fbSMax Filippov #define ELF_ARCH        EM_XTENSA
1944ba7651fbSMax Filippov 
1945ba7651fbSMax Filippov static inline void init_thread(struct target_pt_regs *regs,
1946ba7651fbSMax Filippov                                struct image_info *infop)
1947ba7651fbSMax Filippov {
1948ba7651fbSMax Filippov     regs->windowbase = 0;
1949ba7651fbSMax Filippov     regs->windowstart = 1;
1950ba7651fbSMax Filippov     regs->areg[1] = infop->start_stack;
1951ba7651fbSMax Filippov     regs->pc = infop->entry;
1952d2796be6SMax Filippov     if (info_is_fdpic(infop)) {
1953d2796be6SMax Filippov         regs->areg[4] = infop->loadmap_addr;
1954d2796be6SMax Filippov         regs->areg[5] = infop->interpreter_loadmap_addr;
1955d2796be6SMax Filippov         if (infop->interpreter_loadmap_addr) {
1956d2796be6SMax Filippov             regs->areg[6] = infop->interpreter_pt_dynamic_addr;
1957d2796be6SMax Filippov         } else {
1958d2796be6SMax Filippov             regs->areg[6] = infop->pt_dynamic_addr;
1959d2796be6SMax Filippov         }
1960d2796be6SMax Filippov     }
1961ba7651fbSMax Filippov }
1962ba7651fbSMax Filippov 
1963ba7651fbSMax Filippov /* See linux kernel: arch/xtensa/include/asm/elf.h.  */
1964ba7651fbSMax Filippov #define ELF_NREG 128
1965ba7651fbSMax Filippov typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1966ba7651fbSMax Filippov 
1967ba7651fbSMax Filippov enum {
1968ba7651fbSMax Filippov     TARGET_REG_PC,
1969ba7651fbSMax Filippov     TARGET_REG_PS,
1970ba7651fbSMax Filippov     TARGET_REG_LBEG,
1971ba7651fbSMax Filippov     TARGET_REG_LEND,
1972ba7651fbSMax Filippov     TARGET_REG_LCOUNT,
1973ba7651fbSMax Filippov     TARGET_REG_SAR,
1974ba7651fbSMax Filippov     TARGET_REG_WINDOWSTART,
1975ba7651fbSMax Filippov     TARGET_REG_WINDOWBASE,
1976ba7651fbSMax Filippov     TARGET_REG_THREADPTR,
1977ba7651fbSMax Filippov     TARGET_REG_AR0 = 64,
1978ba7651fbSMax Filippov };
1979ba7651fbSMax Filippov 
1980ba7651fbSMax Filippov static void elf_core_copy_regs(target_elf_gregset_t *regs,
1981ba7651fbSMax Filippov                                const CPUXtensaState *env)
1982ba7651fbSMax Filippov {
1983ba7651fbSMax Filippov     unsigned i;
1984ba7651fbSMax Filippov 
1985ba7651fbSMax Filippov     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
1986ba7651fbSMax Filippov     (*regs)[TARGET_REG_PS] = tswapreg(env->sregs[PS] & ~PS_EXCM);
1987ba7651fbSMax Filippov     (*regs)[TARGET_REG_LBEG] = tswapreg(env->sregs[LBEG]);
1988ba7651fbSMax Filippov     (*regs)[TARGET_REG_LEND] = tswapreg(env->sregs[LEND]);
1989ba7651fbSMax Filippov     (*regs)[TARGET_REG_LCOUNT] = tswapreg(env->sregs[LCOUNT]);
1990ba7651fbSMax Filippov     (*regs)[TARGET_REG_SAR] = tswapreg(env->sregs[SAR]);
1991ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWSTART] = tswapreg(env->sregs[WINDOW_START]);
1992ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWBASE] = tswapreg(env->sregs[WINDOW_BASE]);
1993ba7651fbSMax Filippov     (*regs)[TARGET_REG_THREADPTR] = tswapreg(env->uregs[THREADPTR]);
1994ba7651fbSMax Filippov     xtensa_sync_phys_from_window((CPUXtensaState *)env);
1995ba7651fbSMax Filippov     for (i = 0; i < env->config->nareg; ++i) {
1996ba7651fbSMax Filippov         (*regs)[TARGET_REG_AR0 + i] = tswapreg(env->phys_regs[i]);
1997ba7651fbSMax Filippov     }
1998ba7651fbSMax Filippov }
1999ba7651fbSMax Filippov 
2000ba7651fbSMax Filippov #define USE_ELF_CORE_DUMP
2001ba7651fbSMax Filippov #define ELF_EXEC_PAGESIZE       4096
2002ba7651fbSMax Filippov 
2003ba7651fbSMax Filippov #endif /* TARGET_XTENSA */
2004ba7651fbSMax Filippov 
2005d2a56bd2STaylor Simpson #ifdef TARGET_HEXAGON
2006d2a56bd2STaylor Simpson 
2007d2a56bd2STaylor Simpson #define ELF_CLASS       ELFCLASS32
2008d2a56bd2STaylor Simpson #define ELF_ARCH        EM_HEXAGON
2009d2a56bd2STaylor Simpson 
2010d2a56bd2STaylor Simpson static inline void init_thread(struct target_pt_regs *regs,
2011d2a56bd2STaylor Simpson                                struct image_info *infop)
2012d2a56bd2STaylor Simpson {
2013d2a56bd2STaylor Simpson     regs->sepc = infop->entry;
2014d2a56bd2STaylor Simpson     regs->sp = infop->start_stack;
2015d2a56bd2STaylor Simpson }
2016d2a56bd2STaylor Simpson 
2017d2a56bd2STaylor Simpson #endif /* TARGET_HEXAGON */
2018d2a56bd2STaylor Simpson 
2019fcdc0ab4SJiaxun Yang #ifndef ELF_BASE_PLATFORM
2020fcdc0ab4SJiaxun Yang #define ELF_BASE_PLATFORM (NULL)
2021fcdc0ab4SJiaxun Yang #endif
2022fcdc0ab4SJiaxun Yang 
202315338fd7Sbellard #ifndef ELF_PLATFORM
202415338fd7Sbellard #define ELF_PLATFORM (NULL)
202515338fd7Sbellard #endif
202615338fd7Sbellard 
202775be901cSPeter Crosthwaite #ifndef ELF_MACHINE
202875be901cSPeter Crosthwaite #define ELF_MACHINE ELF_ARCH
202975be901cSPeter Crosthwaite #endif
203075be901cSPeter Crosthwaite 
2031d276a604SPeter Crosthwaite #ifndef elf_check_arch
2032d276a604SPeter Crosthwaite #define elf_check_arch(x) ((x) == ELF_ARCH)
2033d276a604SPeter Crosthwaite #endif
2034d276a604SPeter Crosthwaite 
2035ace3d654SCarlo Marcelo Arenas Belón #ifndef elf_check_abi
2036ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (1)
2037ace3d654SCarlo Marcelo Arenas Belón #endif
2038ace3d654SCarlo Marcelo Arenas Belón 
203915338fd7Sbellard #ifndef ELF_HWCAP
204015338fd7Sbellard #define ELF_HWCAP 0
204115338fd7Sbellard #endif
204215338fd7Sbellard 
20437c4ee5bcSRichard Henderson #ifndef STACK_GROWS_DOWN
20447c4ee5bcSRichard Henderson #define STACK_GROWS_DOWN 1
20457c4ee5bcSRichard Henderson #endif
20467c4ee5bcSRichard Henderson 
20477c4ee5bcSRichard Henderson #ifndef STACK_ALIGNMENT
20487c4ee5bcSRichard Henderson #define STACK_ALIGNMENT 16
20497c4ee5bcSRichard Henderson #endif
20507c4ee5bcSRichard Henderson 
2051992f48a0Sblueswir1 #ifdef TARGET_ABI32
2052cb33da57Sblueswir1 #undef ELF_CLASS
2053992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
2054cb33da57Sblueswir1 #undef bswaptls
2055cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
2056cb33da57Sblueswir1 #endif
2057cb33da57Sblueswir1 
2058872f3d04SRichard Henderson #ifndef EXSTACK_DEFAULT
2059872f3d04SRichard Henderson #define EXSTACK_DEFAULT false
2060872f3d04SRichard Henderson #endif
2061872f3d04SRichard Henderson 
206231e31b8aSbellard #include "elf.h"
206309bfb054Sbellard 
2064e8384b37SRichard Henderson /* We must delay the following stanzas until after "elf.h". */
2065e8384b37SRichard Henderson #if defined(TARGET_AARCH64)
2066e8384b37SRichard Henderson 
2067e8384b37SRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
2068e8384b37SRichard Henderson                                     const uint32_t *data,
2069e8384b37SRichard Henderson                                     struct image_info *info,
2070e8384b37SRichard Henderson                                     Error **errp)
2071e8384b37SRichard Henderson {
2072e8384b37SRichard Henderson     if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
2073e8384b37SRichard Henderson         if (pr_datasz != sizeof(uint32_t)) {
2074e8384b37SRichard Henderson             error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
2075e8384b37SRichard Henderson             return false;
2076e8384b37SRichard Henderson         }
2077e8384b37SRichard Henderson         /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
2078e8384b37SRichard Henderson         info->note_flags = *data;
2079e8384b37SRichard Henderson     }
2080e8384b37SRichard Henderson     return true;
2081e8384b37SRichard Henderson }
2082e8384b37SRichard Henderson #define ARCH_USE_GNU_PROPERTY 1
2083e8384b37SRichard Henderson 
2084e8384b37SRichard Henderson #else
2085e8384b37SRichard Henderson 
208683f990ebSRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
208783f990ebSRichard Henderson                                     const uint32_t *data,
208883f990ebSRichard Henderson                                     struct image_info *info,
208983f990ebSRichard Henderson                                     Error **errp)
209083f990ebSRichard Henderson {
209183f990ebSRichard Henderson     g_assert_not_reached();
209283f990ebSRichard Henderson }
209383f990ebSRichard Henderson #define ARCH_USE_GNU_PROPERTY 0
209483f990ebSRichard Henderson 
2095e8384b37SRichard Henderson #endif
2096e8384b37SRichard Henderson 
209709bfb054Sbellard struct exec
209809bfb054Sbellard {
209909bfb054Sbellard     unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
210009bfb054Sbellard     unsigned int a_text;   /* length of text, in bytes */
210109bfb054Sbellard     unsigned int a_data;   /* length of data, in bytes */
210209bfb054Sbellard     unsigned int a_bss;    /* length of uninitialized data area, in bytes */
210309bfb054Sbellard     unsigned int a_syms;   /* length of symbol table data in file, in bytes */
210409bfb054Sbellard     unsigned int a_entry;  /* start address */
210509bfb054Sbellard     unsigned int a_trsize; /* length of relocation info for text, in bytes */
210609bfb054Sbellard     unsigned int a_drsize; /* length of relocation info for data, in bytes */
210709bfb054Sbellard };
210809bfb054Sbellard 
210909bfb054Sbellard 
211009bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
211109bfb054Sbellard #define OMAGIC 0407
211209bfb054Sbellard #define NMAGIC 0410
211309bfb054Sbellard #define ZMAGIC 0413
211409bfb054Sbellard #define QMAGIC 0314
211509bfb054Sbellard 
2116e0d1673dSLirong Yuan #define DLINFO_ITEMS 16
211731e31b8aSbellard 
211809bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
211909bfb054Sbellard {
212009bfb054Sbellard     memcpy(to, from, n);
212109bfb054Sbellard }
212209bfb054Sbellard 
212331e31b8aSbellard #ifdef BSWAP_NEEDED
212492a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
212531e31b8aSbellard {
212631e31b8aSbellard     bswap16s(&ehdr->e_type);            /* Object file type */
212731e31b8aSbellard     bswap16s(&ehdr->e_machine);         /* Architecture */
212831e31b8aSbellard     bswap32s(&ehdr->e_version);         /* Object file version */
212992a31b1fSbellard     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
213092a31b1fSbellard     bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
213192a31b1fSbellard     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
213231e31b8aSbellard     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
213331e31b8aSbellard     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
213431e31b8aSbellard     bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
213531e31b8aSbellard     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
213631e31b8aSbellard     bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
213731e31b8aSbellard     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
213831e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
213931e31b8aSbellard }
214031e31b8aSbellard 
2141991f8f0cSRichard Henderson static void bswap_phdr(struct elf_phdr *phdr, int phnum)
214231e31b8aSbellard {
2143991f8f0cSRichard Henderson     int i;
2144991f8f0cSRichard Henderson     for (i = 0; i < phnum; ++i, ++phdr) {
214531e31b8aSbellard         bswap32s(&phdr->p_type);        /* Segment type */
2146991f8f0cSRichard Henderson         bswap32s(&phdr->p_flags);       /* Segment flags */
214792a31b1fSbellard         bswaptls(&phdr->p_offset);      /* Segment file offset */
214892a31b1fSbellard         bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
214992a31b1fSbellard         bswaptls(&phdr->p_paddr);       /* Segment physical address */
215092a31b1fSbellard         bswaptls(&phdr->p_filesz);      /* Segment size in file */
215192a31b1fSbellard         bswaptls(&phdr->p_memsz);       /* Segment size in memory */
215292a31b1fSbellard         bswaptls(&phdr->p_align);       /* Segment alignment */
215331e31b8aSbellard     }
2154991f8f0cSRichard Henderson }
2155689f936fSbellard 
2156991f8f0cSRichard Henderson static void bswap_shdr(struct elf_shdr *shdr, int shnum)
2157689f936fSbellard {
2158991f8f0cSRichard Henderson     int i;
2159991f8f0cSRichard Henderson     for (i = 0; i < shnum; ++i, ++shdr) {
2160689f936fSbellard         bswap32s(&shdr->sh_name);
2161689f936fSbellard         bswap32s(&shdr->sh_type);
216292a31b1fSbellard         bswaptls(&shdr->sh_flags);
216392a31b1fSbellard         bswaptls(&shdr->sh_addr);
216492a31b1fSbellard         bswaptls(&shdr->sh_offset);
216592a31b1fSbellard         bswaptls(&shdr->sh_size);
2166689f936fSbellard         bswap32s(&shdr->sh_link);
2167689f936fSbellard         bswap32s(&shdr->sh_info);
216892a31b1fSbellard         bswaptls(&shdr->sh_addralign);
216992a31b1fSbellard         bswaptls(&shdr->sh_entsize);
2170689f936fSbellard     }
2171991f8f0cSRichard Henderson }
2172689f936fSbellard 
21737a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
2174689f936fSbellard {
2175689f936fSbellard     bswap32s(&sym->st_name);
21767a3148a9Sj_mayer     bswaptls(&sym->st_value);
21777a3148a9Sj_mayer     bswaptls(&sym->st_size);
2178689f936fSbellard     bswap16s(&sym->st_shndx);
2179689f936fSbellard }
21805dd0db52SStefan Markovic 
21815dd0db52SStefan Markovic #ifdef TARGET_MIPS
21825dd0db52SStefan Markovic static void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags)
21835dd0db52SStefan Markovic {
21845dd0db52SStefan Markovic     bswap16s(&abiflags->version);
21855dd0db52SStefan Markovic     bswap32s(&abiflags->ases);
21865dd0db52SStefan Markovic     bswap32s(&abiflags->isa_ext);
21875dd0db52SStefan Markovic     bswap32s(&abiflags->flags1);
21885dd0db52SStefan Markovic     bswap32s(&abiflags->flags2);
21895dd0db52SStefan Markovic }
21905dd0db52SStefan Markovic #endif
2191991f8f0cSRichard Henderson #else
2192991f8f0cSRichard Henderson static inline void bswap_ehdr(struct elfhdr *ehdr) { }
2193991f8f0cSRichard Henderson static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
2194991f8f0cSRichard Henderson static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
2195991f8f0cSRichard Henderson static inline void bswap_sym(struct elf_sym *sym) { }
21965dd0db52SStefan Markovic #ifdef TARGET_MIPS
21975dd0db52SStefan Markovic static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { }
21985dd0db52SStefan Markovic #endif
219931e31b8aSbellard #endif
220031e31b8aSbellard 
2201edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
22029349b4f9SAndreas Färber static int elf_core_dump(int, const CPUArchState *);
2203edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
2204682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
2205edf8e2afSMika Westerberg 
22069058abddSRichard Henderson /* Verify the portions of EHDR within E_IDENT for the target.
22079058abddSRichard Henderson    This can be performed before bswapping the entire header.  */
22089058abddSRichard Henderson static bool elf_check_ident(struct elfhdr *ehdr)
22099058abddSRichard Henderson {
22109058abddSRichard Henderson     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
22119058abddSRichard Henderson             && ehdr->e_ident[EI_MAG1] == ELFMAG1
22129058abddSRichard Henderson             && ehdr->e_ident[EI_MAG2] == ELFMAG2
22139058abddSRichard Henderson             && ehdr->e_ident[EI_MAG3] == ELFMAG3
22149058abddSRichard Henderson             && ehdr->e_ident[EI_CLASS] == ELF_CLASS
22159058abddSRichard Henderson             && ehdr->e_ident[EI_DATA] == ELF_DATA
22169058abddSRichard Henderson             && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
22179058abddSRichard Henderson }
22189058abddSRichard Henderson 
22199058abddSRichard Henderson /* Verify the portions of EHDR outside of E_IDENT for the target.
22209058abddSRichard Henderson    This has to wait until after bswapping the header.  */
22219058abddSRichard Henderson static bool elf_check_ehdr(struct elfhdr *ehdr)
22229058abddSRichard Henderson {
22239058abddSRichard Henderson     return (elf_check_arch(ehdr->e_machine)
2224ace3d654SCarlo Marcelo Arenas Belón             && elf_check_abi(ehdr->e_flags)
22259058abddSRichard Henderson             && ehdr->e_ehsize == sizeof(struct elfhdr)
22269058abddSRichard Henderson             && ehdr->e_phentsize == sizeof(struct elf_phdr)
22279058abddSRichard Henderson             && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
22289058abddSRichard Henderson }
22299058abddSRichard Henderson 
223031e31b8aSbellard /*
2231e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
223231e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
223331e31b8aSbellard  * to be put directly into the top of new user memory.
223431e31b8aSbellard  *
223531e31b8aSbellard  */
223659baae9aSStefan Brüns static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch,
223759baae9aSStefan Brüns                                   abi_ulong p, abi_ulong stack_limit)
223831e31b8aSbellard {
223959baae9aSStefan Brüns     char *tmp;
22407c4ee5bcSRichard Henderson     int len, i;
224159baae9aSStefan Brüns     abi_ulong top = p;
224231e31b8aSbellard 
224331e31b8aSbellard     if (!p) {
224431e31b8aSbellard         return 0;       /* bullet-proofing */
224531e31b8aSbellard     }
224659baae9aSStefan Brüns 
22477c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
22487c4ee5bcSRichard Henderson         int offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
22497c4ee5bcSRichard Henderson         for (i = argc - 1; i >= 0; --i) {
22507c4ee5bcSRichard Henderson             tmp = argv[i];
2251edf779ffSbellard             if (!tmp) {
225231e31b8aSbellard                 fprintf(stderr, "VFS: argc is wrong");
225331e31b8aSbellard                 exit(-1);
225431e31b8aSbellard             }
225559baae9aSStefan Brüns             len = strlen(tmp) + 1;
225659baae9aSStefan Brüns             tmp += len;
225759baae9aSStefan Brüns 
225859baae9aSStefan Brüns             if (len > (p - stack_limit)) {
225931e31b8aSbellard                 return 0;
226031e31b8aSbellard             }
226131e31b8aSbellard             while (len) {
226231e31b8aSbellard                 int bytes_to_copy = (len > offset) ? offset : len;
226331e31b8aSbellard                 tmp -= bytes_to_copy;
226431e31b8aSbellard                 p -= bytes_to_copy;
226531e31b8aSbellard                 offset -= bytes_to_copy;
226631e31b8aSbellard                 len -= bytes_to_copy;
226759baae9aSStefan Brüns 
226859baae9aSStefan Brüns                 memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
226959baae9aSStefan Brüns 
227059baae9aSStefan Brüns                 if (offset == 0) {
227159baae9aSStefan Brüns                     memcpy_to_target(p, scratch, top - p);
227259baae9aSStefan Brüns                     top = p;
227359baae9aSStefan Brüns                     offset = TARGET_PAGE_SIZE;
227431e31b8aSbellard                 }
227531e31b8aSbellard             }
227631e31b8aSbellard         }
22777c4ee5bcSRichard Henderson         if (p != top) {
227859baae9aSStefan Brüns             memcpy_to_target(p, scratch + offset, top - p);
227959baae9aSStefan Brüns         }
22807c4ee5bcSRichard Henderson     } else {
22817c4ee5bcSRichard Henderson         int remaining = TARGET_PAGE_SIZE - (p % TARGET_PAGE_SIZE);
22827c4ee5bcSRichard Henderson         for (i = 0; i < argc; ++i) {
22837c4ee5bcSRichard Henderson             tmp = argv[i];
22847c4ee5bcSRichard Henderson             if (!tmp) {
22857c4ee5bcSRichard Henderson                 fprintf(stderr, "VFS: argc is wrong");
22867c4ee5bcSRichard Henderson                 exit(-1);
22877c4ee5bcSRichard Henderson             }
22887c4ee5bcSRichard Henderson             len = strlen(tmp) + 1;
22897c4ee5bcSRichard Henderson             if (len > (stack_limit - p)) {
22907c4ee5bcSRichard Henderson                 return 0;
22917c4ee5bcSRichard Henderson             }
22927c4ee5bcSRichard Henderson             while (len) {
22937c4ee5bcSRichard Henderson                 int bytes_to_copy = (len > remaining) ? remaining : len;
22947c4ee5bcSRichard Henderson 
22957c4ee5bcSRichard Henderson                 memcpy_fromfs(scratch + (p - top), tmp, bytes_to_copy);
22967c4ee5bcSRichard Henderson 
22977c4ee5bcSRichard Henderson                 tmp += bytes_to_copy;
22987c4ee5bcSRichard Henderson                 remaining -= bytes_to_copy;
22997c4ee5bcSRichard Henderson                 p += bytes_to_copy;
23007c4ee5bcSRichard Henderson                 len -= bytes_to_copy;
23017c4ee5bcSRichard Henderson 
23027c4ee5bcSRichard Henderson                 if (remaining == 0) {
23037c4ee5bcSRichard Henderson                     memcpy_to_target(top, scratch, p - top);
23047c4ee5bcSRichard Henderson                     top = p;
23057c4ee5bcSRichard Henderson                     remaining = TARGET_PAGE_SIZE;
23067c4ee5bcSRichard Henderson                 }
23077c4ee5bcSRichard Henderson             }
23087c4ee5bcSRichard Henderson         }
23097c4ee5bcSRichard Henderson         if (p != top) {
23107c4ee5bcSRichard Henderson             memcpy_to_target(top, scratch, p - top);
23117c4ee5bcSRichard Henderson         }
23127c4ee5bcSRichard Henderson     }
231359baae9aSStefan Brüns 
231431e31b8aSbellard     return p;
231531e31b8aSbellard }
231631e31b8aSbellard 
231759baae9aSStefan Brüns /* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of
231859baae9aSStefan Brüns  * argument/environment space. Newer kernels (>2.6.33) allow more,
231959baae9aSStefan Brüns  * dependent on stack size, but guarantee at least 32 pages for
232059baae9aSStefan Brüns  * backwards compatibility.
232159baae9aSStefan Brüns  */
232259baae9aSStefan Brüns #define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE)
232359baae9aSStefan Brüns 
232459baae9aSStefan Brüns static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
232531e31b8aSbellard                                  struct image_info *info)
232631e31b8aSbellard {
232759baae9aSStefan Brüns     abi_ulong size, error, guard;
2328872f3d04SRichard Henderson     int prot;
232931e31b8aSbellard 
2330703e0e89SRichard Henderson     size = guest_stack_size;
233159baae9aSStefan Brüns     if (size < STACK_LOWER_LIMIT) {
233259baae9aSStefan Brüns         size = STACK_LOWER_LIMIT;
233360dcbcb5SRichard Henderson     }
2334f4388205SHelge Deller 
2335f4388205SHelge Deller     if (STACK_GROWS_DOWN) {
233660dcbcb5SRichard Henderson         guard = TARGET_PAGE_SIZE;
23378e3b0cbbSMarc-André Lureau         if (guard < qemu_real_host_page_size()) {
23388e3b0cbbSMarc-André Lureau             guard = qemu_real_host_page_size();
233960dcbcb5SRichard Henderson         }
2340f4388205SHelge Deller     } else {
2341f4388205SHelge Deller         /* no guard page for hppa target where stack grows upwards. */
2342f4388205SHelge Deller         guard = 0;
2343f4388205SHelge Deller     }
234460dcbcb5SRichard Henderson 
2345872f3d04SRichard Henderson     prot = PROT_READ | PROT_WRITE;
2346872f3d04SRichard Henderson     if (info->exec_stack) {
2347872f3d04SRichard Henderson         prot |= PROT_EXEC;
2348872f3d04SRichard Henderson     }
2349872f3d04SRichard Henderson     error = target_mmap(0, size + guard, prot,
235060dcbcb5SRichard Henderson                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
235109bfb054Sbellard     if (error == -1) {
235260dcbcb5SRichard Henderson         perror("mmap stack");
235331e31b8aSbellard         exit(-1);
235431e31b8aSbellard     }
235531e31b8aSbellard 
235660dcbcb5SRichard Henderson     /* We reserve one extra page at the top of the stack as guard.  */
23577c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
235860dcbcb5SRichard Henderson         target_mprotect(error, guard, PROT_NONE);
235960dcbcb5SRichard Henderson         info->stack_limit = error + guard;
236059baae9aSStefan Brüns         return info->stack_limit + size - sizeof(void *);
23617c4ee5bcSRichard Henderson     } else {
23627c4ee5bcSRichard Henderson         info->stack_limit = error + size;
23637c4ee5bcSRichard Henderson         return error;
23647c4ee5bcSRichard Henderson     }
236531e31b8aSbellard }
236631e31b8aSbellard 
23672d385be6SRichard Henderson /**
23682d385be6SRichard Henderson  * zero_bss:
23692d385be6SRichard Henderson  *
23702d385be6SRichard Henderson  * Map and zero the bss.  We need to explicitly zero any fractional pages
23712d385be6SRichard Henderson  * after the data section (i.e. bss).  Return false on mapping failure.
23722d385be6SRichard Henderson  */
2373e6e66b03SRichard Henderson static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss,
2374e6e66b03SRichard Henderson                      int prot, Error **errp)
237531e31b8aSbellard {
23762d385be6SRichard Henderson     abi_ulong align_bss;
2377cf129f3aSRichard Henderson 
2378e6e66b03SRichard Henderson     /* We only expect writable bss; the code segment shouldn't need this. */
2379e6e66b03SRichard Henderson     if (!(prot & PROT_WRITE)) {
2380e6e66b03SRichard Henderson         error_setg(errp, "PT_LOAD with non-writable bss");
2381e6e66b03SRichard Henderson         return false;
2382e6e66b03SRichard Henderson     }
2383e6e66b03SRichard Henderson 
23842d385be6SRichard Henderson     align_bss = TARGET_PAGE_ALIGN(start_bss);
23852d385be6SRichard Henderson     end_bss = TARGET_PAGE_ALIGN(end_bss);
2386cf129f3aSRichard Henderson 
23872d385be6SRichard Henderson     if (start_bss < align_bss) {
23882d385be6SRichard Henderson         int flags = page_get_flags(start_bss);
2389cf129f3aSRichard Henderson 
2390e6e66b03SRichard Henderson         if (!(flags & PAGE_BITS)) {
2391e6e66b03SRichard Henderson             /*
2392e6e66b03SRichard Henderson              * The whole address space of the executable was reserved
2393e6e66b03SRichard Henderson              * at the start, therefore all pages will be VALID.
2394e6e66b03SRichard Henderson              * But assuming there are no PROT_NONE PT_LOAD segments,
2395e6e66b03SRichard Henderson              * a PROT_NONE page means no data all bss, and we can
2396e6e66b03SRichard Henderson              * simply extend the new anon mapping back to the start
2397e6e66b03SRichard Henderson              * of the page of bss.
2398e6e66b03SRichard Henderson              */
23992d385be6SRichard Henderson             align_bss -= TARGET_PAGE_SIZE;
24002d385be6SRichard Henderson         } else {
2401e6e66b03SRichard Henderson             /*
2402e6e66b03SRichard Henderson              * The start of the bss shares a page with something.
2403e6e66b03SRichard Henderson              * The only thing that we expect is the data section,
2404e6e66b03SRichard Henderson              * which would already be marked writable.
2405e6e66b03SRichard Henderson              * Overlapping the RX code segment seems malformed.
2406e6e66b03SRichard Henderson              */
2407e6e66b03SRichard Henderson             if (!(flags & PAGE_WRITE)) {
2408e6e66b03SRichard Henderson                 error_setg(errp, "PT_LOAD with bss overlapping "
2409e6e66b03SRichard Henderson                            "non-writable page");
2410e6e66b03SRichard Henderson                 return false;
2411e6e66b03SRichard Henderson             }
2412e6e66b03SRichard Henderson 
2413e6e66b03SRichard Henderson             /* The page is already mapped and writable. */
2414e6e66b03SRichard Henderson             memset(g2h_untagged(start_bss), 0, align_bss - start_bss);
241531e31b8aSbellard         }
2416f46e9a0bSTom Musta     }
2417cf129f3aSRichard Henderson 
2418e6e66b03SRichard Henderson     if (align_bss < end_bss &&
24192d385be6SRichard Henderson         target_mmap(align_bss, end_bss - align_bss, prot,
2420e6e66b03SRichard Henderson                     MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) {
2421e6e66b03SRichard Henderson         error_setg_errno(errp, errno, "Error mapping bss");
2422e6e66b03SRichard Henderson         return false;
2423e6e66b03SRichard Henderson     }
2424e6e66b03SRichard Henderson     return true;
2425853d6f7aSbellard }
2426853d6f7aSbellard 
2427d2796be6SMax Filippov #if defined(TARGET_ARM)
2428cf58affeSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2429cf58affeSChristophe Lyon {
2430cf58affeSChristophe Lyon     return exec->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC;
2431cf58affeSChristophe Lyon }
2432d2796be6SMax Filippov #elif defined(TARGET_XTENSA)
2433d2796be6SMax Filippov static int elf_is_fdpic(struct elfhdr *exec)
2434d2796be6SMax Filippov {
2435d2796be6SMax Filippov     return exec->e_ident[EI_OSABI] == ELFOSABI_XTENSA_FDPIC;
2436d2796be6SMax Filippov }
2437cf58affeSChristophe Lyon #else
2438a99856cdSChristophe Lyon /* Default implementation, always false.  */
2439a99856cdSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2440a99856cdSChristophe Lyon {
2441a99856cdSChristophe Lyon     return 0;
2442a99856cdSChristophe Lyon }
2443cf58affeSChristophe Lyon #endif
2444a99856cdSChristophe Lyon 
24451af02e83SMike Frysinger static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
24461af02e83SMike Frysinger {
24471af02e83SMike Frysinger     uint16_t n;
24481af02e83SMike Frysinger     struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
24491af02e83SMike Frysinger 
24501af02e83SMike Frysinger     /* elf32_fdpic_loadseg */
24511af02e83SMike Frysinger     n = info->nsegs;
24521af02e83SMike Frysinger     while (n--) {
24531af02e83SMike Frysinger         sp -= 12;
24541af02e83SMike Frysinger         put_user_u32(loadsegs[n].addr, sp+0);
24551af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_vaddr, sp+4);
24561af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_memsz, sp+8);
24571af02e83SMike Frysinger     }
24581af02e83SMike Frysinger 
24591af02e83SMike Frysinger     /* elf32_fdpic_loadmap */
24601af02e83SMike Frysinger     sp -= 4;
24611af02e83SMike Frysinger     put_user_u16(0, sp+0); /* version */
24621af02e83SMike Frysinger     put_user_u16(info->nsegs, sp+2); /* nsegs */
24631af02e83SMike Frysinger 
24641af02e83SMike Frysinger     info->personality = PER_LINUX_FDPIC;
24651af02e83SMike Frysinger     info->loadmap_addr = sp;
24661af02e83SMike Frysinger 
24671af02e83SMike Frysinger     return sp;
24681af02e83SMike Frysinger }
24691af02e83SMike Frysinger 
2470992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
247131e31b8aSbellard                                    struct elfhdr *exec,
24728e62a717SRichard Henderson                                    struct image_info *info,
24738e62a717SRichard Henderson                                    struct image_info *interp_info)
247431e31b8aSbellard {
2475992f48a0Sblueswir1     abi_ulong sp;
24767c4ee5bcSRichard Henderson     abi_ulong u_argc, u_argv, u_envp, u_auxv;
247753a5960aSpbrook     int size;
247814322badSLaurent ALFONSI     int i;
247914322badSLaurent ALFONSI     abi_ulong u_rand_bytes;
248014322badSLaurent ALFONSI     uint8_t k_rand_bytes[16];
2481fcdc0ab4SJiaxun Yang     abi_ulong u_platform, u_base_platform;
2482fcdc0ab4SJiaxun Yang     const char *k_platform, *k_base_platform;
2483863cf0b7Sj_mayer     const int n = sizeof(elf_addr_t);
248431e31b8aSbellard 
248553a5960aSpbrook     sp = p;
24861af02e83SMike Frysinger 
24871af02e83SMike Frysinger     /* Needs to be before we load the env/argc/... */
24881af02e83SMike Frysinger     if (elf_is_fdpic(exec)) {
24891af02e83SMike Frysinger         /* Need 4 byte alignment for these structs */
24901af02e83SMike Frysinger         sp &= ~3;
24911af02e83SMike Frysinger         sp = loader_build_fdpic_loadmap(info, sp);
24921af02e83SMike Frysinger         info->other_info = interp_info;
24931af02e83SMike Frysinger         if (interp_info) {
24941af02e83SMike Frysinger             interp_info->other_info = info;
24951af02e83SMike Frysinger             sp = loader_build_fdpic_loadmap(interp_info, sp);
24963cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = interp_info->loadmap_addr;
24973cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = interp_info->pt_dynamic_addr;
24983cb10cfaSChristophe Lyon         } else {
24993cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = 0;
25003cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = 0;
25011af02e83SMike Frysinger         }
25021af02e83SMike Frysinger     }
25031af02e83SMike Frysinger 
2504fcdc0ab4SJiaxun Yang     u_base_platform = 0;
2505fcdc0ab4SJiaxun Yang     k_base_platform = ELF_BASE_PLATFORM;
2506fcdc0ab4SJiaxun Yang     if (k_base_platform) {
2507fcdc0ab4SJiaxun Yang         size_t len = strlen(k_base_platform) + 1;
2508fcdc0ab4SJiaxun Yang         if (STACK_GROWS_DOWN) {
2509fcdc0ab4SJiaxun Yang             sp -= (len + n - 1) & ~(n - 1);
2510fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2511fcdc0ab4SJiaxun Yang             /* FIXME - check return value of memcpy_to_target() for failure */
2512fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2513fcdc0ab4SJiaxun Yang         } else {
2514fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2515fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2516fcdc0ab4SJiaxun Yang             sp += len + 1;
2517fcdc0ab4SJiaxun Yang         }
2518fcdc0ab4SJiaxun Yang     }
2519fcdc0ab4SJiaxun Yang 
252053a5960aSpbrook     u_platform = 0;
252115338fd7Sbellard     k_platform = ELF_PLATFORM;
252215338fd7Sbellard     if (k_platform) {
252315338fd7Sbellard         size_t len = strlen(k_platform) + 1;
25247c4ee5bcSRichard Henderson         if (STACK_GROWS_DOWN) {
252553a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
252653a5960aSpbrook             u_platform = sp;
2527579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
252853a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
25297c4ee5bcSRichard Henderson         } else {
25307c4ee5bcSRichard Henderson             memcpy_to_target(sp, k_platform, len);
25317c4ee5bcSRichard Henderson             u_platform = sp;
25327c4ee5bcSRichard Henderson             sp += len + 1;
25337c4ee5bcSRichard Henderson         }
25347c4ee5bcSRichard Henderson     }
25357c4ee5bcSRichard Henderson 
25367c4ee5bcSRichard Henderson     /* Provide 16 byte alignment for the PRNG, and basic alignment for
25377c4ee5bcSRichard Henderson      * the argv and envp pointers.
25387c4ee5bcSRichard Henderson      */
25397c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
25407c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_DOWN(sp, 16);
25417c4ee5bcSRichard Henderson     } else {
25427c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp, 16);
254315338fd7Sbellard     }
254414322badSLaurent ALFONSI 
254514322badSLaurent ALFONSI     /*
2546c6a2377fSRichard Henderson      * Generate 16 random bytes for userspace PRNG seeding.
254714322badSLaurent ALFONSI      */
2548c6a2377fSRichard Henderson     qemu_guest_getrandom_nofail(k_rand_bytes, sizeof(k_rand_bytes));
25497c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
255014322badSLaurent ALFONSI         sp -= 16;
255114322badSLaurent ALFONSI         u_rand_bytes = sp;
255214322badSLaurent ALFONSI         /* FIXME - check return value of memcpy_to_target() for failure */
255314322badSLaurent ALFONSI         memcpy_to_target(sp, k_rand_bytes, 16);
25547c4ee5bcSRichard Henderson     } else {
25557c4ee5bcSRichard Henderson         memcpy_to_target(sp, k_rand_bytes, 16);
25567c4ee5bcSRichard Henderson         u_rand_bytes = sp;
25577c4ee5bcSRichard Henderson         sp += 16;
25587c4ee5bcSRichard Henderson     }
255914322badSLaurent ALFONSI 
256053a5960aSpbrook     size = (DLINFO_ITEMS + 1) * 2;
2561fcdc0ab4SJiaxun Yang     if (k_base_platform)
2562fcdc0ab4SJiaxun Yang         size += 2;
256315338fd7Sbellard     if (k_platform)
256453a5960aSpbrook         size += 2;
2565f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
256653a5960aSpbrook     size += DLINFO_ARCH_ITEMS * 2;
2567f5155289Sbellard #endif
2568ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2569ad6919dcSPeter Maydell     size += 2;
2570ad6919dcSPeter Maydell #endif
2571f516511eSPeter Maydell     info->auxv_len = size * n;
2572f516511eSPeter Maydell 
257353a5960aSpbrook     size += envc + argc + 2;
2574b9329d4bSRichard Henderson     size += 1;  /* argc itself */
257553a5960aSpbrook     size *= n;
25767c4ee5bcSRichard Henderson 
25777c4ee5bcSRichard Henderson     /* Allocate space and finalize stack alignment for entry now.  */
25787c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
25797c4ee5bcSRichard Henderson         u_argc = QEMU_ALIGN_DOWN(sp - size, STACK_ALIGNMENT);
25807c4ee5bcSRichard Henderson         sp = u_argc;
25817c4ee5bcSRichard Henderson     } else {
25827c4ee5bcSRichard Henderson         u_argc = sp;
25837c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp + size, STACK_ALIGNMENT);
25847c4ee5bcSRichard Henderson     }
25857c4ee5bcSRichard Henderson 
25867c4ee5bcSRichard Henderson     u_argv = u_argc + n;
25877c4ee5bcSRichard Henderson     u_envp = u_argv + (argc + 1) * n;
25887c4ee5bcSRichard Henderson     u_auxv = u_envp + (envc + 1) * n;
25897c4ee5bcSRichard Henderson     info->saved_auxv = u_auxv;
259060f1c801SRichard Henderson     info->argc = argc;
259160f1c801SRichard Henderson     info->envc = envc;
259260f1c801SRichard Henderson     info->argv = u_argv;
259360f1c801SRichard Henderson     info->envp = u_envp;
2594f5155289Sbellard 
2595863cf0b7Sj_mayer     /* This is correct because Linux defines
2596863cf0b7Sj_mayer      * elf_addr_t as Elf32_Off / Elf64_Off
2597863cf0b7Sj_mayer      */
259853a5960aSpbrook #define NEW_AUX_ENT(id, val) do {               \
25997c4ee5bcSRichard Henderson         put_user_ual(id, u_auxv);  u_auxv += n; \
26007c4ee5bcSRichard Henderson         put_user_ual(val, u_auxv); u_auxv += n; \
260153a5960aSpbrook     } while(0)
26022f619698Sbellard 
260382991bedSPeter Maydell #ifdef ARCH_DLINFO
260482991bedSPeter Maydell     /*
260582991bedSPeter Maydell      * ARCH_DLINFO must come first so platform specific code can enforce
260682991bedSPeter Maydell      * special alignment requirements on the AUXV if necessary (eg. PPC).
260782991bedSPeter Maydell      */
260882991bedSPeter Maydell     ARCH_DLINFO;
260982991bedSPeter Maydell #endif
2610f516511eSPeter Maydell     /* There must be exactly DLINFO_ITEMS entries here, or the assert
2611f516511eSPeter Maydell      * on info->auxv_len will trigger.
2612f516511eSPeter Maydell      */
26138e62a717SRichard Henderson     NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
2614992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
2615992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
261633143c44SLaurent Vivier     if ((info->alignment & ~qemu_host_page_mask) != 0) {
261733143c44SLaurent Vivier         /* Target doesn't support host page size alignment */
261833143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
261933143c44SLaurent Vivier     } else {
262033143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(MAX(TARGET_PAGE_SIZE,
262133143c44SLaurent Vivier                                                qemu_host_page_size)));
262233143c44SLaurent Vivier     }
26238e62a717SRichard Henderson     NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
2624992f48a0Sblueswir1     NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
26258e62a717SRichard Henderson     NEW_AUX_ENT(AT_ENTRY, info->entry);
2626992f48a0Sblueswir1     NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
2627992f48a0Sblueswir1     NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
2628992f48a0Sblueswir1     NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
2629992f48a0Sblueswir1     NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
2630992f48a0Sblueswir1     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
2631a07c67dfSpbrook     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
263214322badSLaurent ALFONSI     NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
2633444cd5c3SMarco A L Barbosa     NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
2634e0d1673dSLirong Yuan     NEW_AUX_ENT(AT_EXECFN, info->file_string);
263514322badSLaurent ALFONSI 
2636ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2637ad6919dcSPeter Maydell     NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
2638ad6919dcSPeter Maydell #endif
2639ad6919dcSPeter Maydell 
2640fcdc0ab4SJiaxun Yang     if (u_base_platform) {
2641fcdc0ab4SJiaxun Yang         NEW_AUX_ENT(AT_BASE_PLATFORM, u_base_platform);
2642fcdc0ab4SJiaxun Yang     }
26437c4ee5bcSRichard Henderson     if (u_platform) {
264453a5960aSpbrook         NEW_AUX_ENT(AT_PLATFORM, u_platform);
26457c4ee5bcSRichard Henderson     }
26467c4ee5bcSRichard Henderson     NEW_AUX_ENT (AT_NULL, 0);
2647f5155289Sbellard #undef NEW_AUX_ENT
2648f5155289Sbellard 
2649f516511eSPeter Maydell     /* Check that our initial calculation of the auxv length matches how much
2650f516511eSPeter Maydell      * we actually put into it.
2651f516511eSPeter Maydell      */
2652f516511eSPeter Maydell     assert(info->auxv_len == u_auxv - info->saved_auxv);
2653edf8e2afSMika Westerberg 
26547c4ee5bcSRichard Henderson     put_user_ual(argc, u_argc);
26557c4ee5bcSRichard Henderson 
26567c4ee5bcSRichard Henderson     p = info->arg_strings;
26577c4ee5bcSRichard Henderson     for (i = 0; i < argc; ++i) {
26587c4ee5bcSRichard Henderson         put_user_ual(p, u_argv);
26597c4ee5bcSRichard Henderson         u_argv += n;
26607c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
26617c4ee5bcSRichard Henderson     }
26627c4ee5bcSRichard Henderson     put_user_ual(0, u_argv);
26637c4ee5bcSRichard Henderson 
26647c4ee5bcSRichard Henderson     p = info->env_strings;
26657c4ee5bcSRichard Henderson     for (i = 0; i < envc; ++i) {
26667c4ee5bcSRichard Henderson         put_user_ual(p, u_envp);
26677c4ee5bcSRichard Henderson         u_envp += n;
26687c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
26697c4ee5bcSRichard Henderson     }
26707c4ee5bcSRichard Henderson     put_user_ual(0, u_envp);
26717c4ee5bcSRichard Henderson 
267231e31b8aSbellard     return sp;
267331e31b8aSbellard }
267431e31b8aSbellard 
2675f5ef0e51SRichard Henderson #if defined(HI_COMMPAGE)
2676eee816c0SRichard Henderson #define LO_COMMPAGE -1
2677f5ef0e51SRichard Henderson #elif defined(LO_COMMPAGE)
267866346fafSRichard Henderson #define HI_COMMPAGE 0
2679f5ef0e51SRichard Henderson #else
2680f5ef0e51SRichard Henderson #define HI_COMMPAGE 0
2681eee816c0SRichard Henderson #define LO_COMMPAGE -1
2682d461b73eSRichard Henderson #ifndef INIT_GUEST_COMMPAGE
2683ee947430SAlex Bennée #define init_guest_commpage() true
2684ee947430SAlex Bennée #endif
2685d461b73eSRichard Henderson #endif
2686ee947430SAlex Bennée 
268706f38c66SRichard Henderson /**
268806f38c66SRichard Henderson  * pgb_try_mmap:
268906f38c66SRichard Henderson  * @addr: host start address
269006f38c66SRichard Henderson  * @addr_last: host last address
269106f38c66SRichard Henderson  * @keep: do not unmap the probe region
269206f38c66SRichard Henderson  *
269306f38c66SRichard Henderson  * Return 1 if [@addr, @addr_last] is not mapped in the host,
269406f38c66SRichard Henderson  * return 0 if it is not available to map, and -1 on mmap error.
269506f38c66SRichard Henderson  * If @keep, the region is left mapped on success, otherwise unmapped.
269606f38c66SRichard Henderson  */
269706f38c66SRichard Henderson static int pgb_try_mmap(uintptr_t addr, uintptr_t addr_last, bool keep)
269806f38c66SRichard Henderson {
269906f38c66SRichard Henderson     size_t size = addr_last - addr + 1;
270006f38c66SRichard Henderson     void *p = mmap((void *)addr, size, PROT_NONE,
270106f38c66SRichard Henderson                    MAP_ANONYMOUS | MAP_PRIVATE |
270206f38c66SRichard Henderson                    MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
270306f38c66SRichard Henderson     int ret;
270406f38c66SRichard Henderson 
270506f38c66SRichard Henderson     if (p == MAP_FAILED) {
270606f38c66SRichard Henderson         return errno == EEXIST ? 0 : -1;
270706f38c66SRichard Henderson     }
270806f38c66SRichard Henderson     ret = p == (void *)addr;
270906f38c66SRichard Henderson     if (!keep || !ret) {
271006f38c66SRichard Henderson         munmap(p, size);
271106f38c66SRichard Henderson     }
271206f38c66SRichard Henderson     return ret;
271306f38c66SRichard Henderson }
271406f38c66SRichard Henderson 
271506f38c66SRichard Henderson /**
271606f38c66SRichard Henderson  * pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t size, uintptr_t brk)
271706f38c66SRichard Henderson  * @addr: host address
271806f38c66SRichard Henderson  * @addr_last: host last address
271906f38c66SRichard Henderson  * @brk: host brk
272006f38c66SRichard Henderson  *
272106f38c66SRichard Henderson  * Like pgb_try_mmap, but additionally reserve some memory following brk.
272206f38c66SRichard Henderson  */
272306f38c66SRichard Henderson static int pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t addr_last,
272406f38c66SRichard Henderson                                  uintptr_t brk, bool keep)
272506f38c66SRichard Henderson {
272606f38c66SRichard Henderson     uintptr_t brk_last = brk + 16 * MiB - 1;
272706f38c66SRichard Henderson 
272806f38c66SRichard Henderson     /* Do not map anything close to the host brk. */
272906f38c66SRichard Henderson     if (addr <= brk_last && brk <= addr_last) {
273006f38c66SRichard Henderson         return 0;
273106f38c66SRichard Henderson     }
273206f38c66SRichard Henderson     return pgb_try_mmap(addr, addr_last, keep);
273306f38c66SRichard Henderson }
273406f38c66SRichard Henderson 
273506f38c66SRichard Henderson /**
273606f38c66SRichard Henderson  * pgb_try_mmap_set:
273706f38c66SRichard Henderson  * @ga: set of guest addrs
273806f38c66SRichard Henderson  * @base: guest_base
273906f38c66SRichard Henderson  * @brk: host brk
274006f38c66SRichard Henderson  *
274106f38c66SRichard Henderson  * Return true if all @ga can be mapped by the host at @base.
274206f38c66SRichard Henderson  * On success, retain the mapping at index 0 for reserved_va.
274306f38c66SRichard Henderson  */
274406f38c66SRichard Henderson 
274506f38c66SRichard Henderson typedef struct PGBAddrs {
274606f38c66SRichard Henderson     uintptr_t bounds[3][2]; /* start/last pairs */
274706f38c66SRichard Henderson     int nbounds;
274806f38c66SRichard Henderson } PGBAddrs;
274906f38c66SRichard Henderson 
275006f38c66SRichard Henderson static bool pgb_try_mmap_set(const PGBAddrs *ga, uintptr_t base, uintptr_t brk)
275106f38c66SRichard Henderson {
275206f38c66SRichard Henderson     for (int i = ga->nbounds - 1; i >= 0; --i) {
275306f38c66SRichard Henderson         if (pgb_try_mmap_skip_brk(ga->bounds[i][0] + base,
275406f38c66SRichard Henderson                                   ga->bounds[i][1] + base,
275506f38c66SRichard Henderson                                   brk, i == 0 && reserved_va) <= 0) {
275606f38c66SRichard Henderson             return false;
275706f38c66SRichard Henderson         }
275806f38c66SRichard Henderson     }
275906f38c66SRichard Henderson     return true;
276006f38c66SRichard Henderson }
276106f38c66SRichard Henderson 
276206f38c66SRichard Henderson /**
276306f38c66SRichard Henderson  * pgb_addr_set:
276406f38c66SRichard Henderson  * @ga: output set of guest addrs
276506f38c66SRichard Henderson  * @guest_loaddr: guest image low address
276606f38c66SRichard Henderson  * @guest_loaddr: guest image high address
276706f38c66SRichard Henderson  * @identity: create for identity mapping
276806f38c66SRichard Henderson  *
276906f38c66SRichard Henderson  * Fill in @ga with the image, COMMPAGE and NULL page.
277006f38c66SRichard Henderson  */
277106f38c66SRichard Henderson static bool pgb_addr_set(PGBAddrs *ga, abi_ulong guest_loaddr,
277206f38c66SRichard Henderson                          abi_ulong guest_hiaddr, bool try_identity)
277306f38c66SRichard Henderson {
277406f38c66SRichard Henderson     int n;
277506f38c66SRichard Henderson 
277606f38c66SRichard Henderson     /*
277706f38c66SRichard Henderson      * With a low commpage, or a guest mapped very low,
277806f38c66SRichard Henderson      * we may not be able to use the identity map.
277906f38c66SRichard Henderson      */
278006f38c66SRichard Henderson     if (try_identity) {
278106f38c66SRichard Henderson         if (LO_COMMPAGE != -1 && LO_COMMPAGE < mmap_min_addr) {
278206f38c66SRichard Henderson             return false;
278306f38c66SRichard Henderson         }
278406f38c66SRichard Henderson         if (guest_loaddr != 0 && guest_loaddr < mmap_min_addr) {
278506f38c66SRichard Henderson             return false;
278606f38c66SRichard Henderson         }
278706f38c66SRichard Henderson     }
278806f38c66SRichard Henderson 
278906f38c66SRichard Henderson     memset(ga, 0, sizeof(*ga));
279006f38c66SRichard Henderson     n = 0;
279106f38c66SRichard Henderson 
279206f38c66SRichard Henderson     if (reserved_va) {
279306f38c66SRichard Henderson         ga->bounds[n][0] = try_identity ? mmap_min_addr : 0;
279406f38c66SRichard Henderson         ga->bounds[n][1] = reserved_va;
279506f38c66SRichard Henderson         n++;
279606f38c66SRichard Henderson         /* LO_COMMPAGE and NULL handled by reserving from 0. */
279706f38c66SRichard Henderson     } else {
279806f38c66SRichard Henderson         /* Add any LO_COMMPAGE or NULL page. */
279906f38c66SRichard Henderson         if (LO_COMMPAGE != -1) {
280006f38c66SRichard Henderson             ga->bounds[n][0] = 0;
280106f38c66SRichard Henderson             ga->bounds[n][1] = LO_COMMPAGE + TARGET_PAGE_SIZE - 1;
280206f38c66SRichard Henderson             n++;
280306f38c66SRichard Henderson         } else if (!try_identity) {
280406f38c66SRichard Henderson             ga->bounds[n][0] = 0;
280506f38c66SRichard Henderson             ga->bounds[n][1] = TARGET_PAGE_SIZE - 1;
280606f38c66SRichard Henderson             n++;
280706f38c66SRichard Henderson         }
280806f38c66SRichard Henderson 
280906f38c66SRichard Henderson         /* Add the guest image for ET_EXEC. */
281006f38c66SRichard Henderson         if (guest_loaddr) {
281106f38c66SRichard Henderson             ga->bounds[n][0] = guest_loaddr;
281206f38c66SRichard Henderson             ga->bounds[n][1] = guest_hiaddr;
281306f38c66SRichard Henderson             n++;
281406f38c66SRichard Henderson         }
281506f38c66SRichard Henderson     }
281606f38c66SRichard Henderson 
281706f38c66SRichard Henderson     /*
281806f38c66SRichard Henderson      * Temporarily disable
281906f38c66SRichard Henderson      *   "comparison is always false due to limited range of data type"
282006f38c66SRichard Henderson      * due to comparison between unsigned and (possible) 0.
282106f38c66SRichard Henderson      */
282206f38c66SRichard Henderson #pragma GCC diagnostic push
282306f38c66SRichard Henderson #pragma GCC diagnostic ignored "-Wtype-limits"
282406f38c66SRichard Henderson 
282506f38c66SRichard Henderson     /* Add any HI_COMMPAGE not covered by reserved_va. */
282606f38c66SRichard Henderson     if (reserved_va < HI_COMMPAGE) {
282706f38c66SRichard Henderson         ga->bounds[n][0] = HI_COMMPAGE & qemu_host_page_mask;
282806f38c66SRichard Henderson         ga->bounds[n][1] = HI_COMMPAGE + TARGET_PAGE_SIZE - 1;
282906f38c66SRichard Henderson         n++;
283006f38c66SRichard Henderson     }
283106f38c66SRichard Henderson 
283206f38c66SRichard Henderson #pragma GCC diagnostic pop
283306f38c66SRichard Henderson 
283406f38c66SRichard Henderson     ga->nbounds = n;
283506f38c66SRichard Henderson     return true;
283606f38c66SRichard Henderson }
283706f38c66SRichard Henderson 
2838ee947430SAlex Bennée static void pgb_fail_in_use(const char *image_name)
2839ee947430SAlex Bennée {
2840ee947430SAlex Bennée     error_report("%s: requires virtual address space that is in use "
2841ee947430SAlex Bennée                  "(omit the -B option or choose a different value)",
2842ee947430SAlex Bennée                  image_name);
2843ee947430SAlex Bennée     exit(EXIT_FAILURE);
2844ee947430SAlex Bennée }
2845ee947430SAlex Bennée 
284606f38c66SRichard Henderson static void pgb_fixed(const char *image_name, uintptr_t guest_loaddr,
284706f38c66SRichard Henderson                       uintptr_t guest_hiaddr, uintptr_t align)
2848ee947430SAlex Bennée {
284906f38c66SRichard Henderson     PGBAddrs ga;
285006f38c66SRichard Henderson     uintptr_t brk = (uintptr_t)sbrk(0);
2851ee947430SAlex Bennée 
2852ee947430SAlex Bennée     if (!QEMU_IS_ALIGNED(guest_base, align)) {
28535ca870b9SRichard Henderson         fprintf(stderr, "Requested guest base %p does not satisfy "
285406f38c66SRichard Henderson                 "host minimum alignment (0x%" PRIxPTR ")\n",
28555ca870b9SRichard Henderson                 (void *)guest_base, align);
2856ee947430SAlex Bennée         exit(EXIT_FAILURE);
2857ee947430SAlex Bennée     }
2858ee947430SAlex Bennée 
285906f38c66SRichard Henderson     if (!pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, !guest_base)
286006f38c66SRichard Henderson         || !pgb_try_mmap_set(&ga, guest_base, brk)) {
2861ee947430SAlex Bennée         pgb_fail_in_use(image_name);
2862ee947430SAlex Bennée     }
2863ee947430SAlex Bennée }
2864ee947430SAlex Bennée 
2865ad592e37SAlex Bennée /**
2866dd558855SRichard Henderson  * pgb_find_fallback:
2867ad592e37SAlex Bennée  *
2868dd558855SRichard Henderson  * This is a fallback method for finding holes in the host address space
2869dd558855SRichard Henderson  * if we don't have the benefit of being able to access /proc/self/map.
2870dd558855SRichard Henderson  * It can potentially take a very long time as we can only dumbly iterate
2871dd558855SRichard Henderson  * up the host address space seeing if the allocation would work.
2872ad592e37SAlex Bennée  */
2873dd558855SRichard Henderson static uintptr_t pgb_find_fallback(const PGBAddrs *ga, uintptr_t align,
2874dd558855SRichard Henderson                                    uintptr_t brk)
2875ad592e37SAlex Bennée {
2876dd558855SRichard Henderson     /* TODO: come up with a better estimate of how much to skip. */
2877dd558855SRichard Henderson     uintptr_t skip = sizeof(uintptr_t) == 4 ? MiB : GiB;
2878ad592e37SAlex Bennée 
2879dd558855SRichard Henderson     for (uintptr_t base = skip; ; base += skip) {
2880dd558855SRichard Henderson         base = ROUND_UP(base, align);
2881dd558855SRichard Henderson         if (pgb_try_mmap_set(ga, base, brk)) {
2882dd558855SRichard Henderson             return base;
2883dd558855SRichard Henderson         }
2884dd558855SRichard Henderson         if (base >= -skip) {
2885dd558855SRichard Henderson             return -1;
2886dd558855SRichard Henderson         }
2887dd558855SRichard Henderson     }
2888dd558855SRichard Henderson }
2889dd558855SRichard Henderson 
2890dd558855SRichard Henderson static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base,
2891dd558855SRichard Henderson                                IntervalTreeRoot *root)
2892dd558855SRichard Henderson {
2893dd558855SRichard Henderson     for (int i = ga->nbounds - 1; i >= 0; --i) {
2894dd558855SRichard Henderson         uintptr_t s = base + ga->bounds[i][0];
2895dd558855SRichard Henderson         uintptr_t l = base + ga->bounds[i][1];
2896dd558855SRichard Henderson         IntervalTreeNode *n;
2897dd558855SRichard Henderson 
2898dd558855SRichard Henderson         if (l < s) {
2899dd558855SRichard Henderson             /* Wraparound. Skip to advance S to mmap_min_addr. */
2900dd558855SRichard Henderson             return mmap_min_addr - s;
2901dd558855SRichard Henderson         }
2902dd558855SRichard Henderson 
2903dd558855SRichard Henderson         n = interval_tree_iter_first(root, s, l);
2904dd558855SRichard Henderson         if (n != NULL) {
2905dd558855SRichard Henderson             /* Conflict.  Skip to advance S to LAST + 1. */
2906dd558855SRichard Henderson             return n->last - s + 1;
2907dd558855SRichard Henderson         }
2908dd558855SRichard Henderson     }
2909dd558855SRichard Henderson     return 0;  /* success */
2910dd558855SRichard Henderson }
2911dd558855SRichard Henderson 
2912dd558855SRichard Henderson static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root,
2913dd558855SRichard Henderson                                 uintptr_t align, uintptr_t brk)
2914dd558855SRichard Henderson {
2915dd558855SRichard Henderson     uintptr_t last = mmap_min_addr;
2916dd558855SRichard Henderson     uintptr_t base, skip;
2917ad592e37SAlex Bennée 
2918ad592e37SAlex Bennée     while (true) {
2919dd558855SRichard Henderson         base = ROUND_UP(last, align);
2920dd558855SRichard Henderson         if (base < last) {
2921ad592e37SAlex Bennée             return -1;
2922ad592e37SAlex Bennée         }
2923dd558855SRichard Henderson 
2924dd558855SRichard Henderson         skip = pgb_try_itree(ga, base, root);
2925dd558855SRichard Henderson         if (skip == 0) {
2926dd558855SRichard Henderson             break;
29272667e069SAlex Bennée         }
2928dd558855SRichard Henderson 
2929dd558855SRichard Henderson         last = base + skip;
2930dd558855SRichard Henderson         if (last < base) {
2931dd558855SRichard Henderson             return -1;
2932ad592e37SAlex Bennée         }
2933ad592e37SAlex Bennée     }
2934ad592e37SAlex Bennée 
2935dd558855SRichard Henderson     /*
2936dd558855SRichard Henderson      * We've chosen 'base' based on holes in the interval tree,
2937dd558855SRichard Henderson      * but we don't yet know if it is a valid host address.
2938dd558855SRichard Henderson      * Because it is the first matching hole, if the host addresses
2939dd558855SRichard Henderson      * are invalid we know there are no further matches.
2940dd558855SRichard Henderson      */
2941dd558855SRichard Henderson     return pgb_try_mmap_set(ga, base, brk) ? base : -1;
2942dd558855SRichard Henderson }
2943dd558855SRichard Henderson 
2944dd558855SRichard Henderson static void pgb_dynamic(const char *image_name, uintptr_t guest_loaddr,
2945dd558855SRichard Henderson                         uintptr_t guest_hiaddr, uintptr_t align)
2946ee947430SAlex Bennée {
2947dd558855SRichard Henderson     IntervalTreeRoot *root;
2948dd558855SRichard Henderson     uintptr_t brk, ret;
2949dd558855SRichard Henderson     PGBAddrs ga;
2950ee947430SAlex Bennée 
2951ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_loaddr, align));
2952ee947430SAlex Bennée 
2953dd558855SRichard Henderson     /* Try the identity map first. */
2954dd558855SRichard Henderson     if (pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, true)) {
2955dd558855SRichard Henderson         brk = (uintptr_t)sbrk(0);
2956dd558855SRichard Henderson         if (pgb_try_mmap_set(&ga, 0, brk)) {
2957dd558855SRichard Henderson             guest_base = 0;
2958dd558855SRichard Henderson             return;
2959dd558855SRichard Henderson         }
2960dd558855SRichard Henderson     }
2961dd558855SRichard Henderson 
2962dd558855SRichard Henderson     /*
2963dd558855SRichard Henderson      * Rebuild the address set for non-identity map.
2964dd558855SRichard Henderson      * This differs in the mapping of the guest NULL page.
2965dd558855SRichard Henderson      */
2966dd558855SRichard Henderson     pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, false);
2967dd558855SRichard Henderson 
2968dd558855SRichard Henderson     root = read_self_maps();
2969ee947430SAlex Bennée 
2970ee947430SAlex Bennée     /* Read brk after we've read the maps, which will malloc. */
2971ee947430SAlex Bennée     brk = (uintptr_t)sbrk(0);
2972ee947430SAlex Bennée 
2973dd558855SRichard Henderson     if (!root) {
2974dd558855SRichard Henderson         ret = pgb_find_fallback(&ga, align, brk);
2975ee947430SAlex Bennée     } else {
2976ee947430SAlex Bennée         /*
2977dd558855SRichard Henderson          * Reserve the area close to the host brk.
2978dd558855SRichard Henderson          * This will be freed with the rest of the tree.
2979ee947430SAlex Bennée          */
2980dd558855SRichard Henderson         IntervalTreeNode *b = g_new0(IntervalTreeNode, 1);
2981dd558855SRichard Henderson         b->start = brk;
2982dd558855SRichard Henderson         b->last = brk + 16 * MiB - 1;
2983dd558855SRichard Henderson         interval_tree_insert(b, root);
2984dd558855SRichard Henderson 
2985dd558855SRichard Henderson         ret = pgb_find_itree(&ga, root, align, brk);
2986dd558855SRichard Henderson         free_self_maps(root);
2987ee947430SAlex Bennée     }
2988ee947430SAlex Bennée 
2989dd558855SRichard Henderson     if (ret == -1) {
2990dd558855SRichard Henderson         int w = TARGET_LONG_BITS / 4;
2991dd558855SRichard Henderson 
2992dd558855SRichard Henderson         error_report("%s: Unable to find a guest_base to satisfy all "
2993dd558855SRichard Henderson                      "guest address mapping requirements", image_name);
2994dd558855SRichard Henderson 
2995dd558855SRichard Henderson         for (int i = 0; i < ga.nbounds; ++i) {
2996dd558855SRichard Henderson             error_printf("  %0*" PRIx64 "-%0*" PRIx64 "\n",
2997dd558855SRichard Henderson                          w, (uint64_t)ga.bounds[i][0],
2998dd558855SRichard Henderson                          w, (uint64_t)ga.bounds[i][1]);
2999dd558855SRichard Henderson         }
3000ee947430SAlex Bennée         exit(EXIT_FAILURE);
3001ee947430SAlex Bennée     }
3002dd558855SRichard Henderson     guest_base = ret;
3003ee947430SAlex Bennée }
3004ee947430SAlex Bennée 
3005ee947430SAlex Bennée void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
3006ee947430SAlex Bennée                       abi_ulong guest_hiaddr)
3007dce10401SMeador Inge {
300830ab9ef2SRichard Henderson     /* In order to use host shmat, we must be able to honor SHMLBA.  */
3009ee947430SAlex Bennée     uintptr_t align = MAX(SHMLBA, qemu_host_page_size);
3010dce10401SMeador Inge 
30110c441aebSRichard Henderson     /* Sanity check the guest binary. */
30120c441aebSRichard Henderson     if (reserved_va) {
30130c441aebSRichard Henderson         if (guest_hiaddr > reserved_va) {
30140c441aebSRichard Henderson             error_report("%s: requires more than reserved virtual "
30150c441aebSRichard Henderson                          "address space (0x%" PRIx64 " > 0x%lx)",
30160c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr, reserved_va);
30170c441aebSRichard Henderson             exit(EXIT_FAILURE);
30180c441aebSRichard Henderson         }
30190c441aebSRichard Henderson     } else {
30200c441aebSRichard Henderson         if (guest_hiaddr != (uintptr_t)guest_hiaddr) {
30210c441aebSRichard Henderson             error_report("%s: requires more virtual address space "
30220c441aebSRichard Henderson                          "than the host can provide (0x%" PRIx64 ")",
30230c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr + 1);
30240c441aebSRichard Henderson             exit(EXIT_FAILURE);
30250c441aebSRichard Henderson         }
30260c441aebSRichard Henderson     }
30270c441aebSRichard Henderson 
3028ee947430SAlex Bennée     if (have_guest_base) {
302906f38c66SRichard Henderson         pgb_fixed(image_name, guest_loaddr, guest_hiaddr, align);
3030293f2060SLuke Shumaker     } else {
3031dd558855SRichard Henderson         pgb_dynamic(image_name, guest_loaddr, guest_hiaddr, align);
3032806d1021SMeador Inge     }
3033806d1021SMeador Inge 
3034ee947430SAlex Bennée     /* Reserve and initialize the commpage. */
3035ee947430SAlex Bennée     if (!init_guest_commpage()) {
303606f38c66SRichard Henderson         /* We have already probed for the commpage being free. */
303706f38c66SRichard Henderson         g_assert_not_reached();
3038dce10401SMeador Inge     }
3039dce10401SMeador Inge 
3040ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_base, align));
3041ee947430SAlex Bennée     qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space "
3042ee947430SAlex Bennée                   "@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
3043dce10401SMeador Inge }
3044dce10401SMeador Inge 
304583f990ebSRichard Henderson enum {
304683f990ebSRichard Henderson     /* The string "GNU\0" as a magic number. */
304783f990ebSRichard Henderson     GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
304883f990ebSRichard Henderson     NOTE_DATA_SZ = 1 * KiB,
304983f990ebSRichard Henderson     NOTE_NAME_SZ = 4,
305083f990ebSRichard Henderson     ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
305183f990ebSRichard Henderson };
305283f990ebSRichard Henderson 
305383f990ebSRichard Henderson /*
305483f990ebSRichard Henderson  * Process a single gnu_property entry.
305583f990ebSRichard Henderson  * Return false for error.
305683f990ebSRichard Henderson  */
305783f990ebSRichard Henderson static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
305883f990ebSRichard Henderson                                struct image_info *info, bool have_prev_type,
305983f990ebSRichard Henderson                                uint32_t *prev_type, Error **errp)
306083f990ebSRichard Henderson {
306183f990ebSRichard Henderson     uint32_t pr_type, pr_datasz, step;
306283f990ebSRichard Henderson 
306383f990ebSRichard Henderson     if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
306483f990ebSRichard Henderson         goto error_data;
306583f990ebSRichard Henderson     }
306683f990ebSRichard Henderson     datasz -= *off;
306783f990ebSRichard Henderson     data += *off / sizeof(uint32_t);
306883f990ebSRichard Henderson 
306983f990ebSRichard Henderson     if (datasz < 2 * sizeof(uint32_t)) {
307083f990ebSRichard Henderson         goto error_data;
307183f990ebSRichard Henderson     }
307283f990ebSRichard Henderson     pr_type = data[0];
307383f990ebSRichard Henderson     pr_datasz = data[1];
307483f990ebSRichard Henderson     data += 2;
307583f990ebSRichard Henderson     datasz -= 2 * sizeof(uint32_t);
307683f990ebSRichard Henderson     step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
307783f990ebSRichard Henderson     if (step > datasz) {
307883f990ebSRichard Henderson         goto error_data;
307983f990ebSRichard Henderson     }
308083f990ebSRichard Henderson 
308183f990ebSRichard Henderson     /* Properties are supposed to be unique and sorted on pr_type. */
308283f990ebSRichard Henderson     if (have_prev_type && pr_type <= *prev_type) {
308383f990ebSRichard Henderson         if (pr_type == *prev_type) {
308483f990ebSRichard Henderson             error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
308583f990ebSRichard Henderson         } else {
308683f990ebSRichard Henderson             error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
308783f990ebSRichard Henderson         }
308883f990ebSRichard Henderson         return false;
308983f990ebSRichard Henderson     }
309083f990ebSRichard Henderson     *prev_type = pr_type;
309183f990ebSRichard Henderson 
309283f990ebSRichard Henderson     if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
309383f990ebSRichard Henderson         return false;
309483f990ebSRichard Henderson     }
309583f990ebSRichard Henderson 
309683f990ebSRichard Henderson     *off += 2 * sizeof(uint32_t) + step;
309783f990ebSRichard Henderson     return true;
309883f990ebSRichard Henderson 
309983f990ebSRichard Henderson  error_data:
310083f990ebSRichard Henderson     error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
310183f990ebSRichard Henderson     return false;
310283f990ebSRichard Henderson }
310383f990ebSRichard Henderson 
310483f990ebSRichard Henderson /* Process NT_GNU_PROPERTY_TYPE_0. */
3105*3bd02386SRichard Henderson static bool parse_elf_properties(const ImageSource *src,
310683f990ebSRichard Henderson                                  struct image_info *info,
310783f990ebSRichard Henderson                                  const struct elf_phdr *phdr,
310883f990ebSRichard Henderson                                  Error **errp)
310983f990ebSRichard Henderson {
311083f990ebSRichard Henderson     union {
311183f990ebSRichard Henderson         struct elf_note nhdr;
311283f990ebSRichard Henderson         uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
311383f990ebSRichard Henderson     } note;
311483f990ebSRichard Henderson 
311583f990ebSRichard Henderson     int n, off, datasz;
311683f990ebSRichard Henderson     bool have_prev_type;
311783f990ebSRichard Henderson     uint32_t prev_type;
311883f990ebSRichard Henderson 
311983f990ebSRichard Henderson     /* Unless the arch requires properties, ignore them. */
312083f990ebSRichard Henderson     if (!ARCH_USE_GNU_PROPERTY) {
312183f990ebSRichard Henderson         return true;
312283f990ebSRichard Henderson     }
312383f990ebSRichard Henderson 
312483f990ebSRichard Henderson     /* If the properties are crazy large, that's too bad. */
312583f990ebSRichard Henderson     n = phdr->p_filesz;
312683f990ebSRichard Henderson     if (n > sizeof(note)) {
312783f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too large");
312883f990ebSRichard Henderson         return false;
312983f990ebSRichard Henderson     }
313083f990ebSRichard Henderson     if (n < sizeof(note.nhdr)) {
313183f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too small");
313283f990ebSRichard Henderson         return false;
313383f990ebSRichard Henderson     }
313483f990ebSRichard Henderson 
3135*3bd02386SRichard Henderson     if (!imgsrc_read(&note, phdr->p_offset, n, src, errp)) {
313683f990ebSRichard Henderson         return false;
313783f990ebSRichard Henderson     }
313883f990ebSRichard Henderson 
313983f990ebSRichard Henderson     /*
314083f990ebSRichard Henderson      * The contents of a valid PT_GNU_PROPERTY is a sequence
314183f990ebSRichard Henderson      * of uint32_t -- swap them all now.
314283f990ebSRichard Henderson      */
314383f990ebSRichard Henderson #ifdef BSWAP_NEEDED
314483f990ebSRichard Henderson     for (int i = 0; i < n / 4; i++) {
314583f990ebSRichard Henderson         bswap32s(note.data + i);
314683f990ebSRichard Henderson     }
314783f990ebSRichard Henderson #endif
314883f990ebSRichard Henderson 
314983f990ebSRichard Henderson     /*
315083f990ebSRichard Henderson      * Note that nhdr is 3 words, and that the "name" described by namesz
315183f990ebSRichard Henderson      * immediately follows nhdr and is thus at the 4th word.  Further, all
315283f990ebSRichard Henderson      * of the inputs to the kernel's round_up are multiples of 4.
315383f990ebSRichard Henderson      */
315483f990ebSRichard Henderson     if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
315583f990ebSRichard Henderson         note.nhdr.n_namesz != NOTE_NAME_SZ ||
315683f990ebSRichard Henderson         note.data[3] != GNU0_MAGIC) {
315783f990ebSRichard Henderson         error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
315883f990ebSRichard Henderson         return false;
315983f990ebSRichard Henderson     }
316083f990ebSRichard Henderson     off = sizeof(note.nhdr) + NOTE_NAME_SZ;
316183f990ebSRichard Henderson 
316283f990ebSRichard Henderson     datasz = note.nhdr.n_descsz + off;
316383f990ebSRichard Henderson     if (datasz > n) {
316483f990ebSRichard Henderson         error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
316583f990ebSRichard Henderson         return false;
316683f990ebSRichard Henderson     }
316783f990ebSRichard Henderson 
316883f990ebSRichard Henderson     have_prev_type = false;
316983f990ebSRichard Henderson     prev_type = 0;
317083f990ebSRichard Henderson     while (1) {
317183f990ebSRichard Henderson         if (off == datasz) {
317283f990ebSRichard Henderson             return true;  /* end, exit ok */
317383f990ebSRichard Henderson         }
317483f990ebSRichard Henderson         if (!parse_elf_property(note.data, &off, datasz, info,
317583f990ebSRichard Henderson                                 have_prev_type, &prev_type, errp)) {
317683f990ebSRichard Henderson             return false;
317783f990ebSRichard Henderson         }
317883f990ebSRichard Henderson         have_prev_type = true;
317983f990ebSRichard Henderson     }
318083f990ebSRichard Henderson }
318183f990ebSRichard Henderson 
3182*3bd02386SRichard Henderson /**
3183*3bd02386SRichard Henderson  * load_elf_image: Load an ELF image into the address space.
3184*3bd02386SRichard Henderson  * @image_name: the filename of the image, to use in error messages.
3185*3bd02386SRichard Henderson  * @src: the ImageSource from which to read.
3186*3bd02386SRichard Henderson  * @info: info collected from the loaded image.
3187*3bd02386SRichard Henderson  * @ehdr: the ELF header, not yet bswapped.
3188*3bd02386SRichard Henderson  * @pinterp_name: record any PT_INTERP string found.
3189*3bd02386SRichard Henderson  *
3190*3bd02386SRichard Henderson  * On return: @info values will be filled in, as necessary or available.
3191*3bd02386SRichard Henderson  */
319231e31b8aSbellard 
3193*3bd02386SRichard Henderson static void load_elf_image(const char *image_name, const ImageSource *src,
319440d487eeSRichard Henderson                            struct image_info *info, struct elfhdr *ehdr,
3195*3bd02386SRichard Henderson                            char **pinterp_name)
319631e31b8aSbellard {
3197*3bd02386SRichard Henderson     g_autofree struct elf_phdr *phdr = NULL;
31988e62a717SRichard Henderson     abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
3199*3bd02386SRichard Henderson     int i, prot_exec;
3200c7f17e7bSRichard Henderson     Error *err = NULL;
320131e31b8aSbellard 
3202*3bd02386SRichard Henderson     /*
3203*3bd02386SRichard Henderson      * First of all, some simple consistency checks.
3204*3bd02386SRichard Henderson      * Note that we rely on the bswapped ehdr staying in bprm_buf,
3205*3bd02386SRichard Henderson      * for later use by load_elf_binary and create_elf_tables.
3206*3bd02386SRichard Henderson      */
3207*3bd02386SRichard Henderson     if (!imgsrc_read(ehdr, 0, sizeof(*ehdr), src, &err)) {
3208*3bd02386SRichard Henderson         goto exit_errmsg;
3209*3bd02386SRichard Henderson     }
32108e62a717SRichard Henderson     if (!elf_check_ident(ehdr)) {
3211c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
32128e62a717SRichard Henderson         goto exit_errmsg;
32138e62a717SRichard Henderson     }
32148e62a717SRichard Henderson     bswap_ehdr(ehdr);
32158e62a717SRichard Henderson     if (!elf_check_ehdr(ehdr)) {
3216c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
32178e62a717SRichard Henderson         goto exit_errmsg;
321831e31b8aSbellard     }
321931e31b8aSbellard 
3220*3bd02386SRichard Henderson     phdr = imgsrc_read_alloc(ehdr->e_phoff,
3221*3bd02386SRichard Henderson                              ehdr->e_phnum * sizeof(struct elf_phdr),
3222*3bd02386SRichard Henderson                              src, &err);
3223*3bd02386SRichard Henderson     if (phdr == NULL) {
3224*3bd02386SRichard Henderson         goto exit_errmsg;
322531e31b8aSbellard     }
32268e62a717SRichard Henderson     bswap_phdr(phdr, ehdr->e_phnum);
322709bfb054Sbellard 
32281af02e83SMike Frysinger     info->nsegs = 0;
32291af02e83SMike Frysinger     info->pt_dynamic_addr = 0;
32301af02e83SMike Frysinger 
323198c1076cSAlex Bennée     mmap_lock();
323298c1076cSAlex Bennée 
32338a1a5274SRichard Henderson     /*
32348a1a5274SRichard Henderson      * Find the maximum size of the image and allocate an appropriate
32358a1a5274SRichard Henderson      * amount of memory to handle that.  Locate the interpreter, if any.
32368a1a5274SRichard Henderson      */
3237682674b8SRichard Henderson     loaddr = -1, hiaddr = 0;
323833143c44SLaurent Vivier     info->alignment = 0;
3239872f3d04SRichard Henderson     info->exec_stack = EXSTACK_DEFAULT;
32408e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; ++i) {
32414d9d535aSRichard Henderson         struct elf_phdr *eppnt = phdr + i;
32424d9d535aSRichard Henderson         if (eppnt->p_type == PT_LOAD) {
32434d9d535aSRichard Henderson             abi_ulong a = eppnt->p_vaddr - eppnt->p_offset;
3244682674b8SRichard Henderson             if (a < loaddr) {
3245682674b8SRichard Henderson                 loaddr = a;
3246682674b8SRichard Henderson             }
3247a3a67f54SRichard Henderson             a = eppnt->p_vaddr + eppnt->p_memsz - 1;
3248682674b8SRichard Henderson             if (a > hiaddr) {
3249682674b8SRichard Henderson                 hiaddr = a;
3250682674b8SRichard Henderson             }
32511af02e83SMike Frysinger             ++info->nsegs;
32524d9d535aSRichard Henderson             info->alignment |= eppnt->p_align;
32538a1a5274SRichard Henderson         } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
32548a1a5274SRichard Henderson             g_autofree char *interp_name = NULL;
32558a1a5274SRichard Henderson 
32568a1a5274SRichard Henderson             if (*pinterp_name) {
3257c7f17e7bSRichard Henderson                 error_setg(&err, "Multiple PT_INTERP entries");
32588a1a5274SRichard Henderson                 goto exit_errmsg;
32598a1a5274SRichard Henderson             }
3260c7f17e7bSRichard Henderson 
3261*3bd02386SRichard Henderson             interp_name = imgsrc_read_alloc(eppnt->p_offset, eppnt->p_filesz,
3262*3bd02386SRichard Henderson                                             src, &err);
3263*3bd02386SRichard Henderson             if (interp_name == NULL) {
3264*3bd02386SRichard Henderson                 goto exit_errmsg;
32658a1a5274SRichard Henderson             }
32668a1a5274SRichard Henderson             if (interp_name[eppnt->p_filesz - 1] != 0) {
3267c7f17e7bSRichard Henderson                 error_setg(&err, "Invalid PT_INTERP entry");
32688a1a5274SRichard Henderson                 goto exit_errmsg;
32698a1a5274SRichard Henderson             }
32708a1a5274SRichard Henderson             *pinterp_name = g_steal_pointer(&interp_name);
327183f990ebSRichard Henderson         } else if (eppnt->p_type == PT_GNU_PROPERTY) {
3272*3bd02386SRichard Henderson             if (!parse_elf_properties(src, info, eppnt, &err)) {
327383f990ebSRichard Henderson                 goto exit_errmsg;
327483f990ebSRichard Henderson             }
3275872f3d04SRichard Henderson         } else if (eppnt->p_type == PT_GNU_STACK) {
3276872f3d04SRichard Henderson             info->exec_stack = eppnt->p_flags & PF_X;
3277682674b8SRichard Henderson         }
3278682674b8SRichard Henderson     }
3279682674b8SRichard Henderson 
32801ea06dedSRichard Henderson     load_addr = loaddr;
32811ea06dedSRichard Henderson 
32826fd59449SRichard Henderson     if (pinterp_name != NULL) {
32836fd59449SRichard Henderson         if (ehdr->e_type == ET_EXEC) {
32846fd59449SRichard Henderson             /*
32856fd59449SRichard Henderson              * Make sure that the low address does not conflict with
32866fd59449SRichard Henderson              * MMAP_MIN_ADDR or the QEMU application itself.
32876fd59449SRichard Henderson              */
32886fd59449SRichard Henderson             probe_guest_base(image_name, loaddr, hiaddr);
3289ee947430SAlex Bennée         } else {
32901ea06dedSRichard Henderson             abi_ulong align;
32911ea06dedSRichard Henderson 
3292ee947430SAlex Bennée             /*
3293ee947430SAlex Bennée              * The binary is dynamic, but we still need to
3294ee947430SAlex Bennée              * select guest_base.  In this case we pass a size.
3295ee947430SAlex Bennée              */
3296ee947430SAlex Bennée             probe_guest_base(image_name, 0, hiaddr - loaddr);
32971ea06dedSRichard Henderson 
32981ea06dedSRichard Henderson             /*
32991ea06dedSRichard Henderson              * Avoid collision with the loader by providing a different
33001ea06dedSRichard Henderson              * default load address.
33011ea06dedSRichard Henderson              */
33021ea06dedSRichard Henderson             load_addr += elf_et_dyn_base;
33031ea06dedSRichard Henderson 
33041ea06dedSRichard Henderson             /*
33051ea06dedSRichard Henderson              * TODO: Better support for mmap alignment is desirable.
33061ea06dedSRichard Henderson              * Since we do not have complete control over the guest
33071ea06dedSRichard Henderson              * address space, we prefer the kernel to choose some address
33081ea06dedSRichard Henderson              * rather than force the use of LOAD_ADDR via MAP_FIXED.
33091ea06dedSRichard Henderson              * But without MAP_FIXED we cannot guarantee alignment,
33101ea06dedSRichard Henderson              * only suggest it.
33111ea06dedSRichard Henderson              */
33121ea06dedSRichard Henderson             align = pow2ceil(info->alignment);
33131ea06dedSRichard Henderson             if (align) {
33141ea06dedSRichard Henderson                 load_addr &= -align;
33151ea06dedSRichard Henderson             }
33166fd59449SRichard Henderson         }
33176fd59449SRichard Henderson     }
33186fd59449SRichard Henderson 
33196fd59449SRichard Henderson     /*
33206fd59449SRichard Henderson      * Reserve address space for all of this.
33216fd59449SRichard Henderson      *
3322ad25051bSRichard Henderson      * In the case of ET_EXEC, we supply MAP_FIXED_NOREPLACE so that we get
3323ad25051bSRichard Henderson      * exactly the address range that is required.  Without reserved_va,
3324ad25051bSRichard Henderson      * the guest address space is not isolated.  We have attempted to avoid
3325ad25051bSRichard Henderson      * conflict with the host program itself via probe_guest_base, but using
3326ad25051bSRichard Henderson      * MAP_FIXED_NOREPLACE instead of MAP_FIXED provides an extra check.
33276fd59449SRichard Henderson      *
33286fd59449SRichard Henderson      * Otherwise this is ET_DYN, and we are searching for a location
33296fd59449SRichard Henderson      * that can hold the memory space required.  If the image is
33301ea06dedSRichard Henderson      * pre-linked, LOAD_ADDR will be non-zero, and the kernel should
33316fd59449SRichard Henderson      * honor that address if it happens to be free.
33326fd59449SRichard Henderson      *
33336fd59449SRichard Henderson      * In both cases, we will overwrite pages in this range with mappings
33346fd59449SRichard Henderson      * from the executable.
33356fd59449SRichard Henderson      */
33361ea06dedSRichard Henderson     load_addr = target_mmap(load_addr, (size_t)hiaddr - loaddr + 1, PROT_NONE,
33376fd59449SRichard Henderson                             MAP_PRIVATE | MAP_ANON | MAP_NORESERVE |
3338ad25051bSRichard Henderson                             (ehdr->e_type == ET_EXEC ? MAP_FIXED_NOREPLACE : 0),
333909bfb054Sbellard                             -1, 0);
3340682674b8SRichard Henderson     if (load_addr == -1) {
3341c7f17e7bSRichard Henderson         goto exit_mmap;
334209bfb054Sbellard     }
3343682674b8SRichard Henderson     load_bias = load_addr - loaddr;
334409bfb054Sbellard 
3345a99856cdSChristophe Lyon     if (elf_is_fdpic(ehdr)) {
33461af02e83SMike Frysinger         struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
33477267c094SAnthony Liguori             g_malloc(sizeof(*loadsegs) * info->nsegs);
33481af02e83SMike Frysinger 
33491af02e83SMike Frysinger         for (i = 0; i < ehdr->e_phnum; ++i) {
33501af02e83SMike Frysinger             switch (phdr[i].p_type) {
33511af02e83SMike Frysinger             case PT_DYNAMIC:
33521af02e83SMike Frysinger                 info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
33531af02e83SMike Frysinger                 break;
33541af02e83SMike Frysinger             case PT_LOAD:
33551af02e83SMike Frysinger                 loadsegs->addr = phdr[i].p_vaddr + load_bias;
33561af02e83SMike Frysinger                 loadsegs->p_vaddr = phdr[i].p_vaddr;
33571af02e83SMike Frysinger                 loadsegs->p_memsz = phdr[i].p_memsz;
33581af02e83SMike Frysinger                 ++loadsegs;
33591af02e83SMike Frysinger                 break;
33601af02e83SMike Frysinger             }
33611af02e83SMike Frysinger         }
33621af02e83SMike Frysinger     }
33631af02e83SMike Frysinger 
33648e62a717SRichard Henderson     info->load_bias = load_bias;
3365dc12567aSJosh Kunz     info->code_offset = load_bias;
3366dc12567aSJosh Kunz     info->data_offset = load_bias;
33678e62a717SRichard Henderson     info->load_addr = load_addr;
33688e62a717SRichard Henderson     info->entry = ehdr->e_entry + load_bias;
33698e62a717SRichard Henderson     info->start_code = -1;
33708e62a717SRichard Henderson     info->end_code = 0;
33718e62a717SRichard Henderson     info->start_data = -1;
33728e62a717SRichard Henderson     info->end_data = 0;
33731f356e8cSHelge Deller     /* Usual start for brk is after all sections of the main executable. */
3374aec338d6SRichard Henderson     info->brk = TARGET_PAGE_ALIGN(hiaddr + load_bias);
3375d8fd2954SPaul Brook     info->elf_flags = ehdr->e_flags;
33768e62a717SRichard Henderson 
3377e8384b37SRichard Henderson     prot_exec = PROT_EXEC;
3378e8384b37SRichard Henderson #ifdef TARGET_AARCH64
3379e8384b37SRichard Henderson     /*
3380e8384b37SRichard Henderson      * If the BTI feature is present, this indicates that the executable
3381e8384b37SRichard Henderson      * pages of the startup binary should be mapped with PROT_BTI, so that
3382e8384b37SRichard Henderson      * branch targets are enforced.
3383e8384b37SRichard Henderson      *
3384e8384b37SRichard Henderson      * The startup binary is either the interpreter or the static executable.
3385e8384b37SRichard Henderson      * The interpreter is responsible for all pages of a dynamic executable.
3386e8384b37SRichard Henderson      *
3387e8384b37SRichard Henderson      * Elf notes are backward compatible to older cpus.
3388e8384b37SRichard Henderson      * Do not enable BTI unless it is supported.
3389e8384b37SRichard Henderson      */
3390e8384b37SRichard Henderson     if ((info->note_flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
3391e8384b37SRichard Henderson         && (pinterp_name == NULL || *pinterp_name == 0)
3392e8384b37SRichard Henderson         && cpu_isar_feature(aa64_bti, ARM_CPU(thread_cpu))) {
3393e8384b37SRichard Henderson         prot_exec |= TARGET_PROT_BTI;
3394e8384b37SRichard Henderson     }
3395e8384b37SRichard Henderson #endif
3396e8384b37SRichard Henderson 
33978e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; i++) {
33988e62a717SRichard Henderson         struct elf_phdr *eppnt = phdr + i;
339931e31b8aSbellard         if (eppnt->p_type == PT_LOAD) {
34005f4e5b34SRichard Henderson             abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
340131e31b8aSbellard             int elf_prot = 0;
340231e31b8aSbellard 
3403e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_R) {
3404e5eaf570SRichard Henderson                 elf_prot |= PROT_READ;
3405e5eaf570SRichard Henderson             }
3406e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_W) {
3407e5eaf570SRichard Henderson                 elf_prot |= PROT_WRITE;
3408e5eaf570SRichard Henderson             }
3409e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_X) {
3410e8384b37SRichard Henderson                 elf_prot |= prot_exec;
3411e5eaf570SRichard Henderson             }
341231e31b8aSbellard 
3413682674b8SRichard Henderson             vaddr = load_bias + eppnt->p_vaddr;
3414e3d97d5cSRichard Henderson             vaddr_po = vaddr & ~TARGET_PAGE_MASK;
3415e3d97d5cSRichard Henderson             vaddr_ps = vaddr & TARGET_PAGE_MASK;
341622d113b5SGiuseppe Musacchio 
341722d113b5SGiuseppe Musacchio             vaddr_ef = vaddr + eppnt->p_filesz;
341822d113b5SGiuseppe Musacchio             vaddr_em = vaddr + eppnt->p_memsz;
3419682674b8SRichard Henderson 
3420d87146bcSGiuseppe Musacchio             /*
342122d113b5SGiuseppe Musacchio              * Some segments may be completely empty, with a non-zero p_memsz
342222d113b5SGiuseppe Musacchio              * but no backing file segment.
3423d87146bcSGiuseppe Musacchio              */
3424d87146bcSGiuseppe Musacchio             if (eppnt->p_filesz != 0) {
3425*3bd02386SRichard Henderson                 error = imgsrc_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
34265f4e5b34SRichard Henderson                                     elf_prot, MAP_PRIVATE | MAP_FIXED,
3427*3bd02386SRichard Henderson                                     src, eppnt->p_offset - vaddr_po);
3428e89f07d3Spbrook                 if (error == -1) {
3429c7f17e7bSRichard Henderson                     goto exit_mmap;
343031e31b8aSbellard                 }
34315f4e5b34SRichard Henderson             }
343231e31b8aSbellard 
34335f4e5b34SRichard Henderson             /* If the load segment requests extra zeros (e.g. bss), map it. */
34345f4e5b34SRichard Henderson             if (vaddr_ef < vaddr_em &&
3435e6e66b03SRichard Henderson                 !zero_bss(vaddr_ef, vaddr_em, elf_prot, &err)) {
3436e6e66b03SRichard Henderson                 goto exit_errmsg;
3437682674b8SRichard Henderson             }
34388e62a717SRichard Henderson 
34398e62a717SRichard Henderson             /* Find the full program boundaries.  */
34408e62a717SRichard Henderson             if (elf_prot & PROT_EXEC) {
34418e62a717SRichard Henderson                 if (vaddr < info->start_code) {
34428e62a717SRichard Henderson                     info->start_code = vaddr;
3443cf129f3aSRichard Henderson                 }
34448e62a717SRichard Henderson                 if (vaddr_ef > info->end_code) {
34458e62a717SRichard Henderson                     info->end_code = vaddr_ef;
34468e62a717SRichard Henderson                 }
34478e62a717SRichard Henderson             }
34488e62a717SRichard Henderson             if (elf_prot & PROT_WRITE) {
34498e62a717SRichard Henderson                 if (vaddr < info->start_data) {
34508e62a717SRichard Henderson                     info->start_data = vaddr;
34518e62a717SRichard Henderson                 }
34528e62a717SRichard Henderson                 if (vaddr_ef > info->end_data) {
34538e62a717SRichard Henderson                     info->end_data = vaddr_ef;
34548e62a717SRichard Henderson                 }
34558a045188STimothy E Baldwin             }
34565dd0db52SStefan Markovic #ifdef TARGET_MIPS
34575dd0db52SStefan Markovic         } else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
34585dd0db52SStefan Markovic             Mips_elf_abiflags_v0 abiflags;
3459*3bd02386SRichard Henderson 
3460*3bd02386SRichard Henderson             if (!imgsrc_read(&abiflags, eppnt->p_offset, sizeof(abiflags),
3461*3bd02386SRichard Henderson                              src, &err)) {
34625dd0db52SStefan Markovic                 goto exit_errmsg;
34635dd0db52SStefan Markovic             }
34645dd0db52SStefan Markovic             bswap_mips_abiflags(&abiflags);
3465c94cb6c9SStefan Markovic             info->fp_abi = abiflags.fp_abi;
34665dd0db52SStefan Markovic #endif
34678e62a717SRichard Henderson         }
34688e62a717SRichard Henderson     }
34698e62a717SRichard Henderson 
34708e62a717SRichard Henderson     if (info->end_data == 0) {
34718e62a717SRichard Henderson         info->start_data = info->end_code;
34728e62a717SRichard Henderson         info->end_data = info->end_code;
347331e31b8aSbellard     }
347431e31b8aSbellard 
3475682674b8SRichard Henderson     if (qemu_log_enabled()) {
3476*3bd02386SRichard Henderson         load_symbols(ehdr, src->fd, load_bias);
3477682674b8SRichard Henderson     }
347831e31b8aSbellard 
3479*3bd02386SRichard Henderson     debuginfo_report_elf(image_name, src->fd, load_bias);
34807c10cb38SIlya Leoshkevich 
348198c1076cSAlex Bennée     mmap_unlock();
348298c1076cSAlex Bennée 
3483*3bd02386SRichard Henderson     close(src->fd);
34848e62a717SRichard Henderson     return;
348531e31b8aSbellard 
3486c7f17e7bSRichard Henderson  exit_mmap:
3487c7f17e7bSRichard Henderson     error_setg_errno(&err, errno, "Error mapping file");
3488c7f17e7bSRichard Henderson     goto exit_errmsg;
34898e62a717SRichard Henderson  exit_errmsg:
3490c7f17e7bSRichard Henderson     error_reportf_err(err, "%s: ", image_name);
34918e62a717SRichard Henderson     exit(-1);
34928e62a717SRichard Henderson }
34938e62a717SRichard Henderson 
34948e62a717SRichard Henderson static void load_elf_interp(const char *filename, struct image_info *info,
34958e62a717SRichard Henderson                             char bprm_buf[BPRM_BUF_SIZE])
34968e62a717SRichard Henderson {
349740d487eeSRichard Henderson     struct elfhdr ehdr;
3498*3bd02386SRichard Henderson     ImageSource src;
34998e62a717SRichard Henderson     int fd, retval;
3500808f6563SRichard Henderson     Error *err = NULL;
35018e62a717SRichard Henderson 
35028e62a717SRichard Henderson     fd = open(path(filename), O_RDONLY);
35038e62a717SRichard Henderson     if (fd < 0) {
3504808f6563SRichard Henderson         error_setg_file_open(&err, errno, filename);
3505808f6563SRichard Henderson         error_report_err(err);
3506808f6563SRichard Henderson         exit(-1);
35078e62a717SRichard Henderson     }
35088e62a717SRichard Henderson 
35098e62a717SRichard Henderson     retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
35108e62a717SRichard Henderson     if (retval < 0) {
3511808f6563SRichard Henderson         error_setg_errno(&err, errno, "Error reading file header");
3512808f6563SRichard Henderson         error_reportf_err(err, "%s: ", filename);
3513808f6563SRichard Henderson         exit(-1);
35148e62a717SRichard Henderson     }
3515808f6563SRichard Henderson 
3516*3bd02386SRichard Henderson     src.fd = fd;
3517*3bd02386SRichard Henderson     src.cache = bprm_buf;
3518*3bd02386SRichard Henderson     src.cache_size = retval;
35198e62a717SRichard Henderson 
3520*3bd02386SRichard Henderson     load_elf_image(filename, &src, info, &ehdr, NULL);
352131e31b8aSbellard }
352231e31b8aSbellard 
352349918a75Spbrook static int symfind(const void *s0, const void *s1)
352449918a75Spbrook {
352549918a75Spbrook     struct elf_sym *sym = (struct elf_sym *)s1;
3526b6235a75SRichard Henderson     __typeof(sym->st_value) addr = *(uint64_t *)s0;
352749918a75Spbrook     int result = 0;
3528b6235a75SRichard Henderson 
3529c7c530cdSStefan Weil     if (addr < sym->st_value) {
353049918a75Spbrook         result = -1;
3531c7c530cdSStefan Weil     } else if (addr >= sym->st_value + sym->st_size) {
353249918a75Spbrook         result = 1;
353349918a75Spbrook     }
353449918a75Spbrook     return result;
353549918a75Spbrook }
353649918a75Spbrook 
3537b6235a75SRichard Henderson static const char *lookup_symbolxx(struct syminfo *s, uint64_t orig_addr)
353849918a75Spbrook {
353949918a75Spbrook #if ELF_CLASS == ELFCLASS32
354049918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf32;
354149918a75Spbrook #else
354249918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf64;
354349918a75Spbrook #endif
354449918a75Spbrook 
354549918a75Spbrook     // binary search
354649918a75Spbrook     struct elf_sym *sym;
354749918a75Spbrook 
3548c7c530cdSStefan Weil     sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
35497cba04f6SBlue Swirl     if (sym != NULL) {
355049918a75Spbrook         return s->disas_strtab + sym->st_name;
355149918a75Spbrook     }
355249918a75Spbrook 
355349918a75Spbrook     return "";
355449918a75Spbrook }
355549918a75Spbrook 
355649918a75Spbrook /* FIXME: This should use elf_ops.h  */
355749918a75Spbrook static int symcmp(const void *s0, const void *s1)
355849918a75Spbrook {
355949918a75Spbrook     struct elf_sym *sym0 = (struct elf_sym *)s0;
356049918a75Spbrook     struct elf_sym *sym1 = (struct elf_sym *)s1;
356149918a75Spbrook     return (sym0->st_value < sym1->st_value)
356249918a75Spbrook         ? -1
356349918a75Spbrook         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
356449918a75Spbrook }
356549918a75Spbrook 
3566689f936fSbellard /* Best attempt to load symbols from this ELF object. */
3567682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
3568689f936fSbellard {
3569682674b8SRichard Henderson     int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
35701e06262dSPeter Maydell     uint64_t segsz;
3571682674b8SRichard Henderson     struct elf_shdr *shdr;
3572b9475279SCédric VINCENT     char *strings = NULL;
3573b9475279SCédric VINCENT     struct syminfo *s = NULL;
3574b9475279SCédric VINCENT     struct elf_sym *new_syms, *syms = NULL;
357531e31b8aSbellard 
3576682674b8SRichard Henderson     shnum = hdr->e_shnum;
3577682674b8SRichard Henderson     i = shnum * sizeof(struct elf_shdr);
3578682674b8SRichard Henderson     shdr = (struct elf_shdr *)alloca(i);
3579682674b8SRichard Henderson     if (pread(fd, shdr, i, hdr->e_shoff) != i) {
3580689f936fSbellard         return;
3581682674b8SRichard Henderson     }
3582682674b8SRichard Henderson 
3583682674b8SRichard Henderson     bswap_shdr(shdr, shnum);
3584682674b8SRichard Henderson     for (i = 0; i < shnum; ++i) {
3585682674b8SRichard Henderson         if (shdr[i].sh_type == SHT_SYMTAB) {
3586682674b8SRichard Henderson             sym_idx = i;
3587682674b8SRichard Henderson             str_idx = shdr[i].sh_link;
3588689f936fSbellard             goto found;
3589689f936fSbellard         }
3590689f936fSbellard     }
3591682674b8SRichard Henderson 
3592682674b8SRichard Henderson     /* There will be no symbol table if the file was stripped.  */
3593682674b8SRichard Henderson     return;
3594689f936fSbellard 
3595689f936fSbellard  found:
3596689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them.  */
35970ef9ea29SPeter Maydell     s = g_try_new(struct syminfo, 1);
3598682674b8SRichard Henderson     if (!s) {
3599b9475279SCédric VINCENT         goto give_up;
3600682674b8SRichard Henderson     }
3601682674b8SRichard Henderson 
36021e06262dSPeter Maydell     segsz = shdr[str_idx].sh_size;
36031e06262dSPeter Maydell     s->disas_strtab = strings = g_try_malloc(segsz);
36041e06262dSPeter Maydell     if (!strings ||
36051e06262dSPeter Maydell         pread(fd, strings, segsz, shdr[str_idx].sh_offset) != segsz) {
3606b9475279SCédric VINCENT         goto give_up;
3607682674b8SRichard Henderson     }
3608689f936fSbellard 
36091e06262dSPeter Maydell     segsz = shdr[sym_idx].sh_size;
36101e06262dSPeter Maydell     syms = g_try_malloc(segsz);
36111e06262dSPeter Maydell     if (!syms || pread(fd, syms, segsz, shdr[sym_idx].sh_offset) != segsz) {
3612b9475279SCédric VINCENT         goto give_up;
3613682674b8SRichard Henderson     }
3614689f936fSbellard 
36151e06262dSPeter Maydell     if (segsz / sizeof(struct elf_sym) > INT_MAX) {
36161e06262dSPeter Maydell         /* Implausibly large symbol table: give up rather than ploughing
36171e06262dSPeter Maydell          * on with the number of symbols calculation overflowing
36181e06262dSPeter Maydell          */
36191e06262dSPeter Maydell         goto give_up;
36201e06262dSPeter Maydell     }
36211e06262dSPeter Maydell     nsyms = segsz / sizeof(struct elf_sym);
3622682674b8SRichard Henderson     for (i = 0; i < nsyms; ) {
362349918a75Spbrook         bswap_sym(syms + i);
3624682674b8SRichard Henderson         /* Throw away entries which we do not need.  */
3625682674b8SRichard Henderson         if (syms[i].st_shndx == SHN_UNDEF
3626682674b8SRichard Henderson             || syms[i].st_shndx >= SHN_LORESERVE
3627682674b8SRichard Henderson             || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
3628682674b8SRichard Henderson             if (i < --nsyms) {
362949918a75Spbrook                 syms[i] = syms[nsyms];
363049918a75Spbrook             }
3631682674b8SRichard Henderson         } else {
363249918a75Spbrook #if defined(TARGET_ARM) || defined (TARGET_MIPS)
363349918a75Spbrook             /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
363449918a75Spbrook             syms[i].st_value &= ~(target_ulong)1;
363549918a75Spbrook #endif
3636682674b8SRichard Henderson             syms[i].st_value += load_bias;
363749918a75Spbrook             i++;
363849918a75Spbrook         }
3639682674b8SRichard Henderson     }
364049918a75Spbrook 
3641b9475279SCédric VINCENT     /* No "useful" symbol.  */
3642b9475279SCédric VINCENT     if (nsyms == 0) {
3643b9475279SCédric VINCENT         goto give_up;
3644b9475279SCédric VINCENT     }
3645b9475279SCédric VINCENT 
36465d5c9930SRichard Henderson     /* Attempt to free the storage associated with the local symbols
36475d5c9930SRichard Henderson        that we threw away.  Whether or not this has any effect on the
36485d5c9930SRichard Henderson        memory allocation depends on the malloc implementation and how
36495d5c9930SRichard Henderson        many symbols we managed to discard.  */
36500ef9ea29SPeter Maydell     new_syms = g_try_renew(struct elf_sym, syms, nsyms);
36518d79de6eSStefan Weil     if (new_syms == NULL) {
3652b9475279SCédric VINCENT         goto give_up;
36535d5c9930SRichard Henderson     }
36548d79de6eSStefan Weil     syms = new_syms;
36555d5c9930SRichard Henderson 
365649918a75Spbrook     qsort(syms, nsyms, sizeof(*syms), symcmp);
365749918a75Spbrook 
365849918a75Spbrook     s->disas_num_syms = nsyms;
365949918a75Spbrook #if ELF_CLASS == ELFCLASS32
366049918a75Spbrook     s->disas_symtab.elf32 = syms;
366149918a75Spbrook #else
366249918a75Spbrook     s->disas_symtab.elf64 = syms;
366349918a75Spbrook #endif
3664682674b8SRichard Henderson     s->lookup_symbol = lookup_symbolxx;
3665e80cfcfcSbellard     s->next = syminfos;
3666e80cfcfcSbellard     syminfos = s;
3667b9475279SCédric VINCENT 
3668b9475279SCédric VINCENT     return;
3669b9475279SCédric VINCENT 
3670b9475279SCédric VINCENT give_up:
36710ef9ea29SPeter Maydell     g_free(s);
36720ef9ea29SPeter Maydell     g_free(strings);
36730ef9ea29SPeter Maydell     g_free(syms);
3674689f936fSbellard }
367531e31b8aSbellard 
3676768fe76eSYunQiang Su uint32_t get_elf_eflags(int fd)
3677768fe76eSYunQiang Su {
3678768fe76eSYunQiang Su     struct elfhdr ehdr;
3679768fe76eSYunQiang Su     off_t offset;
3680768fe76eSYunQiang Su     int ret;
3681768fe76eSYunQiang Su 
3682768fe76eSYunQiang Su     /* Read ELF header */
3683768fe76eSYunQiang Su     offset = lseek(fd, 0, SEEK_SET);
3684768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3685768fe76eSYunQiang Su         return 0;
3686768fe76eSYunQiang Su     }
3687768fe76eSYunQiang Su     ret = read(fd, &ehdr, sizeof(ehdr));
3688768fe76eSYunQiang Su     if (ret < sizeof(ehdr)) {
3689768fe76eSYunQiang Su         return 0;
3690768fe76eSYunQiang Su     }
3691768fe76eSYunQiang Su     offset = lseek(fd, offset, SEEK_SET);
3692768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3693768fe76eSYunQiang Su         return 0;
3694768fe76eSYunQiang Su     }
3695768fe76eSYunQiang Su 
3696768fe76eSYunQiang Su     /* Check ELF signature */
3697768fe76eSYunQiang Su     if (!elf_check_ident(&ehdr)) {
3698768fe76eSYunQiang Su         return 0;
3699768fe76eSYunQiang Su     }
3700768fe76eSYunQiang Su 
3701768fe76eSYunQiang Su     /* check header */
3702768fe76eSYunQiang Su     bswap_ehdr(&ehdr);
3703768fe76eSYunQiang Su     if (!elf_check_ehdr(&ehdr)) {
3704768fe76eSYunQiang Su         return 0;
3705768fe76eSYunQiang Su     }
3706768fe76eSYunQiang Su 
3707768fe76eSYunQiang Su     /* return architecture id */
3708768fe76eSYunQiang Su     return ehdr.e_flags;
3709768fe76eSYunQiang Su }
3710768fe76eSYunQiang Su 
3711f0116c54SWill Newton int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
371231e31b8aSbellard {
371340d487eeSRichard Henderson     /*
371440d487eeSRichard Henderson      * We need a copy of the elf header for passing to create_elf_tables.
371540d487eeSRichard Henderson      * We will have overwritten the original when we re-use bprm->buf
371640d487eeSRichard Henderson      * while loading the interpreter.  Allocate the storage for this now
371740d487eeSRichard Henderson      * and let elf_load_image do any swapping that may be required.
371840d487eeSRichard Henderson      */
371940d487eeSRichard Henderson     struct elfhdr ehdr;
37208e62a717SRichard Henderson     struct image_info interp_info;
37218e62a717SRichard Henderson     char *elf_interpreter = NULL;
372259baae9aSStefan Brüns     char *scratch;
372331e31b8aSbellard 
3724abcac736SDaniel Santos     memset(&interp_info, 0, sizeof(interp_info));
3725abcac736SDaniel Santos #ifdef TARGET_MIPS
3726abcac736SDaniel Santos     interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
3727abcac736SDaniel Santos #endif
3728abcac736SDaniel Santos 
3729*3bd02386SRichard Henderson     load_elf_image(bprm->filename, &bprm->src, info, &ehdr, &elf_interpreter);
373031e31b8aSbellard 
373159baae9aSStefan Brüns     /* Do this so that we can load the interpreter, if need be.  We will
373259baae9aSStefan Brüns        change some of these later */
373359baae9aSStefan Brüns     bprm->p = setup_arg_pages(bprm, info);
373459baae9aSStefan Brüns 
373559baae9aSStefan Brüns     scratch = g_new0(char, TARGET_PAGE_SIZE);
37367c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
373759baae9aSStefan Brüns         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
373859baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
37397c4ee5bcSRichard Henderson         info->file_string = bprm->p;
374059baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
374159baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
37427c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
374359baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
374459baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
37457c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
37467c4ee5bcSRichard Henderson     } else {
37477c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
37487c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
37497c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
37507c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
37517c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
37527c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
37537c4ee5bcSRichard Henderson         info->file_string = bprm->p;
37547c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
37557c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
37567c4ee5bcSRichard Henderson     }
37577c4ee5bcSRichard Henderson 
375859baae9aSStefan Brüns     g_free(scratch);
375959baae9aSStefan Brüns 
3760e5fe0c52Spbrook     if (!bprm->p) {
3761bf858897SRichard Henderson         fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
376231e31b8aSbellard         exit(-1);
37639955ffacSRichard Henderson     }
3764379f6698SPaul Brook 
37658e62a717SRichard Henderson     if (elf_interpreter) {
37668e62a717SRichard Henderson         load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
376731e31b8aSbellard 
37681f356e8cSHelge Deller         /*
37691f356e8cSHelge Deller          * While unusual because of ELF_ET_DYN_BASE, if we are unlucky
37701f356e8cSHelge Deller          * with the mappings the interpreter can be loaded above but
37711f356e8cSHelge Deller          * near the main executable, which can leave very little room
37721f356e8cSHelge Deller          * for the heap.
37731f356e8cSHelge Deller          * If the current brk has less than 16MB, use the end of the
37741f356e8cSHelge Deller          * interpreter.
37751f356e8cSHelge Deller          */
37761f356e8cSHelge Deller         if (interp_info.brk > info->brk &&
37771f356e8cSHelge Deller             interp_info.load_bias - info->brk < 16 * MiB)  {
37781f356e8cSHelge Deller             info->brk = interp_info.brk;
37791f356e8cSHelge Deller         }
37801f356e8cSHelge Deller 
37818e62a717SRichard Henderson         /* If the program interpreter is one of these two, then assume
37828e62a717SRichard Henderson            an iBCS2 image.  Otherwise assume a native linux image.  */
378331e31b8aSbellard 
37848e62a717SRichard Henderson         if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
37858e62a717SRichard Henderson             || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
37868e62a717SRichard Henderson             info->personality = PER_SVR4;
37878e62a717SRichard Henderson 
378831e31b8aSbellard             /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
37898e62a717SRichard Henderson                and some applications "depend" upon this behavior.  Since
37908e62a717SRichard Henderson                we do not have the power to recompile these, we emulate
37918e62a717SRichard Henderson                the SVr4 behavior.  Sigh.  */
37928e62a717SRichard Henderson             target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
379368754b44SPeter Maydell                         MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
379431e31b8aSbellard         }
3795c94cb6c9SStefan Markovic #ifdef TARGET_MIPS
3796c94cb6c9SStefan Markovic         info->interp_fp_abi = interp_info.fp_abi;
3797c94cb6c9SStefan Markovic #endif
37988e62a717SRichard Henderson     }
379931e31b8aSbellard 
3800db2af69dSRichard Henderson     /*
3801db2af69dSRichard Henderson      * TODO: load a vdso, which would also contain the signal trampolines.
3802db2af69dSRichard Henderson      * Otherwise, allocate a private page to hold them.
3803db2af69dSRichard Henderson      */
3804db2af69dSRichard Henderson     if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
3805802ae45eSLaurent Vivier         abi_long tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
3806db2af69dSRichard Henderson                                           PROT_READ | PROT_WRITE,
3807db2af69dSRichard Henderson                                           MAP_PRIVATE | MAP_ANON, -1, 0);
3808802ae45eSLaurent Vivier         if (tramp_page == -1) {
3809802ae45eSLaurent Vivier             return -errno;
3810802ae45eSLaurent Vivier         }
3811802ae45eSLaurent Vivier 
3812db2af69dSRichard Henderson         setup_sigtramp(tramp_page);
3813db2af69dSRichard Henderson         target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
3814db2af69dSRichard Henderson     }
3815db2af69dSRichard Henderson 
381640d487eeSRichard Henderson     bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &ehdr,
38178e62a717SRichard Henderson                                 info, (elf_interpreter ? &interp_info : NULL));
38188e62a717SRichard Henderson     info->start_stack = bprm->p;
38198e62a717SRichard Henderson 
38208e62a717SRichard Henderson     /* If we have an interpreter, set that as the program's entry point.
38218e78064eSRichard Henderson        Copy the load_bias as well, to help PPC64 interpret the entry
38228e62a717SRichard Henderson        point as a function descriptor.  Do this after creating elf tables
38238e62a717SRichard Henderson        so that we copy the original program entry point into the AUXV.  */
38248e62a717SRichard Henderson     if (elf_interpreter) {
38258e78064eSRichard Henderson         info->load_bias = interp_info.load_bias;
38268e62a717SRichard Henderson         info->entry = interp_info.entry;
38272b323087SPhilippe Mathieu-Daudé         g_free(elf_interpreter);
38288e62a717SRichard Henderson     }
382931e31b8aSbellard 
3830edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3831edf8e2afSMika Westerberg     bprm->core_dump = &elf_core_dump;
3832edf8e2afSMika Westerberg #endif
3833edf8e2afSMika Westerberg 
383431e31b8aSbellard     return 0;
383531e31b8aSbellard }
383631e31b8aSbellard 
3837edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3838edf8e2afSMika Westerberg /*
3839edf8e2afSMika Westerberg  * Definitions to generate Intel SVR4-like core files.
3840a2547a13SLaurent Desnogues  * These mostly have the same names as the SVR4 types with "target_elf_"
3841edf8e2afSMika Westerberg  * tacked on the front to prevent clashes with linux definitions,
3842edf8e2afSMika Westerberg  * and the typedef forms have been avoided.  This is mostly like
3843edf8e2afSMika Westerberg  * the SVR4 structure, but more Linuxy, with things that Linux does
3844edf8e2afSMika Westerberg  * not support and which gdb doesn't really use excluded.
3845edf8e2afSMika Westerberg  *
3846edf8e2afSMika Westerberg  * Fields we don't dump (their contents is zero) in linux-user qemu
3847edf8e2afSMika Westerberg  * are marked with XXX.
3848edf8e2afSMika Westerberg  *
3849edf8e2afSMika Westerberg  * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
3850edf8e2afSMika Westerberg  *
3851edf8e2afSMika Westerberg  * Porting ELF coredump for target is (quite) simple process.  First you
3852dd0a3651SNathan Froyd  * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
3853edf8e2afSMika Westerberg  * the target resides):
3854edf8e2afSMika Westerberg  *
3855edf8e2afSMika Westerberg  * #define USE_ELF_CORE_DUMP
3856edf8e2afSMika Westerberg  *
3857edf8e2afSMika Westerberg  * Next you define type of register set used for dumping.  ELF specification
3858edf8e2afSMika Westerberg  * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
3859edf8e2afSMika Westerberg  *
3860c227f099SAnthony Liguori  * typedef <target_regtype> target_elf_greg_t;
3861edf8e2afSMika Westerberg  * #define ELF_NREG <number of registers>
3862c227f099SAnthony Liguori  * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
3863edf8e2afSMika Westerberg  *
3864edf8e2afSMika Westerberg  * Last step is to implement target specific function that copies registers
3865edf8e2afSMika Westerberg  * from given cpu into just specified register set.  Prototype is:
3866edf8e2afSMika Westerberg  *
3867c227f099SAnthony Liguori  * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
38689349b4f9SAndreas Färber  *                                const CPUArchState *env);
3869edf8e2afSMika Westerberg  *
3870edf8e2afSMika Westerberg  * Parameters:
3871edf8e2afSMika Westerberg  *     regs - copy register values into here (allocated and zeroed by caller)
3872edf8e2afSMika Westerberg  *     env - copy registers from here
3873edf8e2afSMika Westerberg  *
3874edf8e2afSMika Westerberg  * Example for ARM target is provided in this file.
3875edf8e2afSMika Westerberg  */
3876edf8e2afSMika Westerberg 
3877edf8e2afSMika Westerberg /* An ELF note in memory */
3878edf8e2afSMika Westerberg struct memelfnote {
3879edf8e2afSMika Westerberg     const char *name;
3880edf8e2afSMika Westerberg     size_t     namesz;
3881edf8e2afSMika Westerberg     size_t     namesz_rounded;
3882edf8e2afSMika Westerberg     int        type;
3883edf8e2afSMika Westerberg     size_t     datasz;
388480f5ce75SLaurent Vivier     size_t     datasz_rounded;
3885edf8e2afSMika Westerberg     void       *data;
3886edf8e2afSMika Westerberg     size_t     notesz;
3887edf8e2afSMika Westerberg };
3888edf8e2afSMika Westerberg 
3889a2547a13SLaurent Desnogues struct target_elf_siginfo {
3890f8fd4fc4SPaolo Bonzini     abi_int    si_signo; /* signal number */
3891f8fd4fc4SPaolo Bonzini     abi_int    si_code;  /* extra code */
3892f8fd4fc4SPaolo Bonzini     abi_int    si_errno; /* errno */
3893edf8e2afSMika Westerberg };
3894edf8e2afSMika Westerberg 
3895a2547a13SLaurent Desnogues struct target_elf_prstatus {
3896a2547a13SLaurent Desnogues     struct target_elf_siginfo pr_info;      /* Info associated with signal */
38971ddd592fSPaolo Bonzini     abi_short          pr_cursig;    /* Current signal */
3898ca98ac83SPaolo Bonzini     abi_ulong          pr_sigpend;   /* XXX */
3899ca98ac83SPaolo Bonzini     abi_ulong          pr_sighold;   /* XXX */
3900c227f099SAnthony Liguori     target_pid_t       pr_pid;
3901c227f099SAnthony Liguori     target_pid_t       pr_ppid;
3902c227f099SAnthony Liguori     target_pid_t       pr_pgrp;
3903c227f099SAnthony Liguori     target_pid_t       pr_sid;
3904edf8e2afSMika Westerberg     struct target_timeval pr_utime;  /* XXX User time */
3905edf8e2afSMika Westerberg     struct target_timeval pr_stime;  /* XXX System time */
3906edf8e2afSMika Westerberg     struct target_timeval pr_cutime; /* XXX Cumulative user time */
3907edf8e2afSMika Westerberg     struct target_timeval pr_cstime; /* XXX Cumulative system time */
3908c227f099SAnthony Liguori     target_elf_gregset_t      pr_reg;       /* GP registers */
3909f8fd4fc4SPaolo Bonzini     abi_int            pr_fpvalid;   /* XXX */
3910edf8e2afSMika Westerberg };
3911edf8e2afSMika Westerberg 
3912edf8e2afSMika Westerberg #define ELF_PRARGSZ     (80) /* Number of chars for args */
3913edf8e2afSMika Westerberg 
3914a2547a13SLaurent Desnogues struct target_elf_prpsinfo {
3915edf8e2afSMika Westerberg     char         pr_state;       /* numeric process state */
3916edf8e2afSMika Westerberg     char         pr_sname;       /* char for pr_state */
3917edf8e2afSMika Westerberg     char         pr_zomb;        /* zombie */
3918edf8e2afSMika Westerberg     char         pr_nice;        /* nice val */
3919ca98ac83SPaolo Bonzini     abi_ulong    pr_flag;        /* flags */
3920c227f099SAnthony Liguori     target_uid_t pr_uid;
3921c227f099SAnthony Liguori     target_gid_t pr_gid;
3922c227f099SAnthony Liguori     target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
3923edf8e2afSMika Westerberg     /* Lots missing */
3924d7eb2b92SAlistair Francis     char    pr_fname[16] QEMU_NONSTRING; /* filename of executable */
3925edf8e2afSMika Westerberg     char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
3926edf8e2afSMika Westerberg };
3927edf8e2afSMika Westerberg 
3928edf8e2afSMika Westerberg /* Here is the structure in which status of each thread is captured. */
3929edf8e2afSMika Westerberg struct elf_thread_status {
393072cf2d4fSBlue Swirl     QTAILQ_ENTRY(elf_thread_status)  ets_link;
3931a2547a13SLaurent Desnogues     struct target_elf_prstatus prstatus;   /* NT_PRSTATUS */
3932edf8e2afSMika Westerberg #if 0
3933edf8e2afSMika Westerberg     elf_fpregset_t fpu;             /* NT_PRFPREG */
3934edf8e2afSMika Westerberg     struct task_struct *thread;
3935edf8e2afSMika Westerberg     elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
3936edf8e2afSMika Westerberg #endif
3937edf8e2afSMika Westerberg     struct memelfnote notes[1];
3938edf8e2afSMika Westerberg     int num_notes;
3939edf8e2afSMika Westerberg };
3940edf8e2afSMika Westerberg 
3941edf8e2afSMika Westerberg struct elf_note_info {
3942edf8e2afSMika Westerberg     struct memelfnote   *notes;
3943a2547a13SLaurent Desnogues     struct target_elf_prstatus *prstatus;  /* NT_PRSTATUS */
3944a2547a13SLaurent Desnogues     struct target_elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
3945edf8e2afSMika Westerberg 
3946b58deb34SPaolo Bonzini     QTAILQ_HEAD(, elf_thread_status) thread_list;
3947edf8e2afSMika Westerberg #if 0
3948edf8e2afSMika Westerberg     /*
3949edf8e2afSMika Westerberg      * Current version of ELF coredump doesn't support
3950edf8e2afSMika Westerberg      * dumping fp regs etc.
3951edf8e2afSMika Westerberg      */
3952edf8e2afSMika Westerberg     elf_fpregset_t *fpu;
3953edf8e2afSMika Westerberg     elf_fpxregset_t *xfpu;
3954edf8e2afSMika Westerberg     int thread_status_size;
3955edf8e2afSMika Westerberg #endif
3956edf8e2afSMika Westerberg     int notes_size;
3957edf8e2afSMika Westerberg     int numnote;
3958edf8e2afSMika Westerberg };
3959edf8e2afSMika Westerberg 
3960edf8e2afSMika Westerberg struct vm_area_struct {
39611a1c4db9SMikhail Ilyin     target_ulong   vma_start;  /* start vaddr of memory region */
39621a1c4db9SMikhail Ilyin     target_ulong   vma_end;    /* end vaddr of memory region */
3963edf8e2afSMika Westerberg     abi_ulong      vma_flags;  /* protection etc. flags for the region */
396472cf2d4fSBlue Swirl     QTAILQ_ENTRY(vm_area_struct) vma_link;
3965edf8e2afSMika Westerberg };
3966edf8e2afSMika Westerberg 
3967edf8e2afSMika Westerberg struct mm_struct {
396872cf2d4fSBlue Swirl     QTAILQ_HEAD(, vm_area_struct) mm_mmap;
3969edf8e2afSMika Westerberg     int mm_count;           /* number of mappings */
3970edf8e2afSMika Westerberg };
3971edf8e2afSMika Westerberg 
3972edf8e2afSMika Westerberg static struct mm_struct *vma_init(void);
3973edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *);
39741a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *, target_ulong,
39751a1c4db9SMikhail Ilyin                            target_ulong, abi_ulong);
3976edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *);
3977edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *);
3978edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *);
3979edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *);
39801a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
3981edf8e2afSMika Westerberg                       unsigned long flags);
3982edf8e2afSMika Westerberg 
3983edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
3984edf8e2afSMika Westerberg static void fill_note(struct memelfnote *, const char *, int,
3985edf8e2afSMika Westerberg                       unsigned int, void *);
3986a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
3987a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
3988edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *, const TaskState *);
3989edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
3990edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *);
3991edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *);
39929349b4f9SAndreas Färber static int fill_note_info(struct elf_note_info *, long, const CPUArchState *);
39939349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *, const CPUArchState *);
3994edf8e2afSMika Westerberg 
3995edf8e2afSMika Westerberg static int dump_write(int, const void *, size_t);
3996edf8e2afSMika Westerberg static int write_note(struct memelfnote *, int);
3997edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *, int);
3998edf8e2afSMika Westerberg 
3999edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
4000a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *prstatus)
4001edf8e2afSMika Westerberg {
4002ca98ac83SPaolo Bonzini     prstatus->pr_info.si_signo = tswap32(prstatus->pr_info.si_signo);
4003ca98ac83SPaolo Bonzini     prstatus->pr_info.si_code = tswap32(prstatus->pr_info.si_code);
4004ca98ac83SPaolo Bonzini     prstatus->pr_info.si_errno = tswap32(prstatus->pr_info.si_errno);
4005edf8e2afSMika Westerberg     prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
4006ca98ac83SPaolo Bonzini     prstatus->pr_sigpend = tswapal(prstatus->pr_sigpend);
4007ca98ac83SPaolo Bonzini     prstatus->pr_sighold = tswapal(prstatus->pr_sighold);
4008edf8e2afSMika Westerberg     prstatus->pr_pid = tswap32(prstatus->pr_pid);
4009edf8e2afSMika Westerberg     prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
4010edf8e2afSMika Westerberg     prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
4011edf8e2afSMika Westerberg     prstatus->pr_sid = tswap32(prstatus->pr_sid);
4012edf8e2afSMika Westerberg     /* cpu times are not filled, so we skip them */
4013edf8e2afSMika Westerberg     /* regs should be in correct format already */
4014edf8e2afSMika Westerberg     prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
4015edf8e2afSMika Westerberg }
4016edf8e2afSMika Westerberg 
4017a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
4018edf8e2afSMika Westerberg {
4019ca98ac83SPaolo Bonzini     psinfo->pr_flag = tswapal(psinfo->pr_flag);
4020edf8e2afSMika Westerberg     psinfo->pr_uid = tswap16(psinfo->pr_uid);
4021edf8e2afSMika Westerberg     psinfo->pr_gid = tswap16(psinfo->pr_gid);
4022edf8e2afSMika Westerberg     psinfo->pr_pid = tswap32(psinfo->pr_pid);
4023edf8e2afSMika Westerberg     psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
4024edf8e2afSMika Westerberg     psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
4025edf8e2afSMika Westerberg     psinfo->pr_sid = tswap32(psinfo->pr_sid);
4026edf8e2afSMika Westerberg }
4027991f8f0cSRichard Henderson 
4028991f8f0cSRichard Henderson static void bswap_note(struct elf_note *en)
4029991f8f0cSRichard Henderson {
4030991f8f0cSRichard Henderson     bswap32s(&en->n_namesz);
4031991f8f0cSRichard Henderson     bswap32s(&en->n_descsz);
4032991f8f0cSRichard Henderson     bswap32s(&en->n_type);
4033991f8f0cSRichard Henderson }
4034991f8f0cSRichard Henderson #else
4035991f8f0cSRichard Henderson static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
4036991f8f0cSRichard Henderson static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
4037991f8f0cSRichard Henderson static inline void bswap_note(struct elf_note *en) { }
4038edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
4039edf8e2afSMika Westerberg 
4040edf8e2afSMika Westerberg /*
4041edf8e2afSMika Westerberg  * Minimal support for linux memory regions.  These are needed
4042edf8e2afSMika Westerberg  * when we are finding out what memory exactly belongs to
4043edf8e2afSMika Westerberg  * emulated process.  No locks needed here, as long as
4044edf8e2afSMika Westerberg  * thread that received the signal is stopped.
4045edf8e2afSMika Westerberg  */
4046edf8e2afSMika Westerberg 
4047edf8e2afSMika Westerberg static struct mm_struct *vma_init(void)
4048edf8e2afSMika Westerberg {
4049edf8e2afSMika Westerberg     struct mm_struct *mm;
4050edf8e2afSMika Westerberg 
40517267c094SAnthony Liguori     if ((mm = g_malloc(sizeof (*mm))) == NULL)
4052edf8e2afSMika Westerberg         return (NULL);
4053edf8e2afSMika Westerberg 
4054edf8e2afSMika Westerberg     mm->mm_count = 0;
405572cf2d4fSBlue Swirl     QTAILQ_INIT(&mm->mm_mmap);
4056edf8e2afSMika Westerberg 
4057edf8e2afSMika Westerberg     return (mm);
4058edf8e2afSMika Westerberg }
4059edf8e2afSMika Westerberg 
4060edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *mm)
4061edf8e2afSMika Westerberg {
4062edf8e2afSMika Westerberg     struct vm_area_struct *vma;
4063edf8e2afSMika Westerberg 
4064edf8e2afSMika Westerberg     while ((vma = vma_first(mm)) != NULL) {
406572cf2d4fSBlue Swirl         QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
40667267c094SAnthony Liguori         g_free(vma);
4067edf8e2afSMika Westerberg     }
40687267c094SAnthony Liguori     g_free(mm);
4069edf8e2afSMika Westerberg }
4070edf8e2afSMika Westerberg 
40711a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *mm, target_ulong start,
40721a1c4db9SMikhail Ilyin                            target_ulong end, abi_ulong flags)
4073edf8e2afSMika Westerberg {
4074edf8e2afSMika Westerberg     struct vm_area_struct *vma;
4075edf8e2afSMika Westerberg 
40767267c094SAnthony Liguori     if ((vma = g_malloc0(sizeof (*vma))) == NULL)
4077edf8e2afSMika Westerberg         return (-1);
4078edf8e2afSMika Westerberg 
4079edf8e2afSMika Westerberg     vma->vma_start = start;
4080edf8e2afSMika Westerberg     vma->vma_end = end;
4081edf8e2afSMika Westerberg     vma->vma_flags = flags;
4082edf8e2afSMika Westerberg 
408372cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
4084edf8e2afSMika Westerberg     mm->mm_count++;
4085edf8e2afSMika Westerberg 
4086edf8e2afSMika Westerberg     return (0);
4087edf8e2afSMika Westerberg }
4088edf8e2afSMika Westerberg 
4089edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *mm)
4090edf8e2afSMika Westerberg {
409172cf2d4fSBlue Swirl     return (QTAILQ_FIRST(&mm->mm_mmap));
4092edf8e2afSMika Westerberg }
4093edf8e2afSMika Westerberg 
4094edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
4095edf8e2afSMika Westerberg {
409672cf2d4fSBlue Swirl     return (QTAILQ_NEXT(vma, vma_link));
4097edf8e2afSMika Westerberg }
4098edf8e2afSMika Westerberg 
4099edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *mm)
4100edf8e2afSMika Westerberg {
4101edf8e2afSMika Westerberg     return (mm->mm_count);
4102edf8e2afSMika Westerberg }
4103edf8e2afSMika Westerberg 
4104edf8e2afSMika Westerberg /*
4105edf8e2afSMika Westerberg  * Calculate file (dump) size of given memory region.
4106edf8e2afSMika Westerberg  */
4107edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
4108edf8e2afSMika Westerberg {
4109edf8e2afSMika Westerberg     /* if we cannot even read the first page, skip it */
4110c7169b02SRichard Henderson     if (!access_ok_untagged(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
4111edf8e2afSMika Westerberg         return (0);
4112edf8e2afSMika Westerberg 
4113edf8e2afSMika Westerberg     /*
4114edf8e2afSMika Westerberg      * Usually we don't dump executable pages as they contain
4115edf8e2afSMika Westerberg      * non-writable code that debugger can read directly from
4116edf8e2afSMika Westerberg      * target library etc.  However, thread stacks are marked
4117edf8e2afSMika Westerberg      * also executable so we read in first page of given region
4118edf8e2afSMika Westerberg      * and check whether it contains elf header.  If there is
4119edf8e2afSMika Westerberg      * no elf header, we dump it.
4120edf8e2afSMika Westerberg      */
4121edf8e2afSMika Westerberg     if (vma->vma_flags & PROT_EXEC) {
4122edf8e2afSMika Westerberg         char page[TARGET_PAGE_SIZE];
4123edf8e2afSMika Westerberg 
4124022625a8SPeter Maydell         if (copy_from_user(page, vma->vma_start, sizeof (page))) {
4125022625a8SPeter Maydell             return 0;
4126022625a8SPeter Maydell         }
4127edf8e2afSMika Westerberg         if ((page[EI_MAG0] == ELFMAG0) &&
4128edf8e2afSMika Westerberg             (page[EI_MAG1] == ELFMAG1) &&
4129edf8e2afSMika Westerberg             (page[EI_MAG2] == ELFMAG2) &&
4130edf8e2afSMika Westerberg             (page[EI_MAG3] == ELFMAG3)) {
4131edf8e2afSMika Westerberg             /*
4132edf8e2afSMika Westerberg              * Mappings are possibly from ELF binary.  Don't dump
4133edf8e2afSMika Westerberg              * them.
4134edf8e2afSMika Westerberg              */
4135edf8e2afSMika Westerberg             return (0);
4136edf8e2afSMika Westerberg         }
4137edf8e2afSMika Westerberg     }
4138edf8e2afSMika Westerberg 
4139edf8e2afSMika Westerberg     return (vma->vma_end - vma->vma_start);
4140edf8e2afSMika Westerberg }
4141edf8e2afSMika Westerberg 
41421a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
4143edf8e2afSMika Westerberg                       unsigned long flags)
4144edf8e2afSMika Westerberg {
4145edf8e2afSMika Westerberg     struct mm_struct *mm = (struct mm_struct *)priv;
4146edf8e2afSMika Westerberg 
4147edf8e2afSMika Westerberg     vma_add_mapping(mm, start, end, flags);
4148edf8e2afSMika Westerberg     return (0);
4149edf8e2afSMika Westerberg }
4150edf8e2afSMika Westerberg 
4151edf8e2afSMika Westerberg static void fill_note(struct memelfnote *note, const char *name, int type,
4152edf8e2afSMika Westerberg                       unsigned int sz, void *data)
4153edf8e2afSMika Westerberg {
4154edf8e2afSMika Westerberg     unsigned int namesz;
4155edf8e2afSMika Westerberg 
4156edf8e2afSMika Westerberg     namesz = strlen(name) + 1;
4157edf8e2afSMika Westerberg     note->name = name;
4158edf8e2afSMika Westerberg     note->namesz = namesz;
4159edf8e2afSMika Westerberg     note->namesz_rounded = roundup(namesz, sizeof (int32_t));
4160edf8e2afSMika Westerberg     note->type = type;
416180f5ce75SLaurent Vivier     note->datasz = sz;
416280f5ce75SLaurent Vivier     note->datasz_rounded = roundup(sz, sizeof (int32_t));
416380f5ce75SLaurent Vivier 
4164edf8e2afSMika Westerberg     note->data = data;
4165edf8e2afSMika Westerberg 
4166edf8e2afSMika Westerberg     /*
4167edf8e2afSMika Westerberg      * We calculate rounded up note size here as specified by
4168edf8e2afSMika Westerberg      * ELF document.
4169edf8e2afSMika Westerberg      */
4170edf8e2afSMika Westerberg     note->notesz = sizeof (struct elf_note) +
417180f5ce75SLaurent Vivier         note->namesz_rounded + note->datasz_rounded;
4172edf8e2afSMika Westerberg }
4173edf8e2afSMika Westerberg 
4174edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
4175edf8e2afSMika Westerberg                             uint32_t flags)
4176edf8e2afSMika Westerberg {
4177edf8e2afSMika Westerberg     (void) memset(elf, 0, sizeof(*elf));
4178edf8e2afSMika Westerberg 
4179edf8e2afSMika Westerberg     (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
4180edf8e2afSMika Westerberg     elf->e_ident[EI_CLASS] = ELF_CLASS;
4181edf8e2afSMika Westerberg     elf->e_ident[EI_DATA] = ELF_DATA;
4182edf8e2afSMika Westerberg     elf->e_ident[EI_VERSION] = EV_CURRENT;
4183edf8e2afSMika Westerberg     elf->e_ident[EI_OSABI] = ELF_OSABI;
4184edf8e2afSMika Westerberg 
4185edf8e2afSMika Westerberg     elf->e_type = ET_CORE;
4186edf8e2afSMika Westerberg     elf->e_machine = machine;
4187edf8e2afSMika Westerberg     elf->e_version = EV_CURRENT;
4188edf8e2afSMika Westerberg     elf->e_phoff = sizeof(struct elfhdr);
4189edf8e2afSMika Westerberg     elf->e_flags = flags;
4190edf8e2afSMika Westerberg     elf->e_ehsize = sizeof(struct elfhdr);
4191edf8e2afSMika Westerberg     elf->e_phentsize = sizeof(struct elf_phdr);
4192edf8e2afSMika Westerberg     elf->e_phnum = segs;
4193edf8e2afSMika Westerberg 
4194edf8e2afSMika Westerberg     bswap_ehdr(elf);
4195edf8e2afSMika Westerberg }
4196edf8e2afSMika Westerberg 
4197edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
4198edf8e2afSMika Westerberg {
4199edf8e2afSMika Westerberg     phdr->p_type = PT_NOTE;
4200edf8e2afSMika Westerberg     phdr->p_offset = offset;
4201edf8e2afSMika Westerberg     phdr->p_vaddr = 0;
4202edf8e2afSMika Westerberg     phdr->p_paddr = 0;
4203edf8e2afSMika Westerberg     phdr->p_filesz = sz;
4204edf8e2afSMika Westerberg     phdr->p_memsz = 0;
4205edf8e2afSMika Westerberg     phdr->p_flags = 0;
4206edf8e2afSMika Westerberg     phdr->p_align = 0;
4207edf8e2afSMika Westerberg 
4208991f8f0cSRichard Henderson     bswap_phdr(phdr, 1);
4209edf8e2afSMika Westerberg }
4210edf8e2afSMika Westerberg 
4211edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *note)
4212edf8e2afSMika Westerberg {
4213edf8e2afSMika Westerberg     return (note->notesz);
4214edf8e2afSMika Westerberg }
4215edf8e2afSMika Westerberg 
4216a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *prstatus,
4217edf8e2afSMika Westerberg                           const TaskState *ts, int signr)
4218edf8e2afSMika Westerberg {
4219edf8e2afSMika Westerberg     (void) memset(prstatus, 0, sizeof (*prstatus));
4220edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
4221edf8e2afSMika Westerberg     prstatus->pr_pid = ts->ts_tid;
4222edf8e2afSMika Westerberg     prstatus->pr_ppid = getppid();
4223edf8e2afSMika Westerberg     prstatus->pr_pgrp = getpgrp();
4224edf8e2afSMika Westerberg     prstatus->pr_sid = getsid(0);
4225edf8e2afSMika Westerberg 
4226edf8e2afSMika Westerberg     bswap_prstatus(prstatus);
4227edf8e2afSMika Westerberg }
4228edf8e2afSMika Westerberg 
4229a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
4230edf8e2afSMika Westerberg {
4231900cfbcaSJim Meyering     char *base_filename;
4232edf8e2afSMika Westerberg     unsigned int i, len;
4233edf8e2afSMika Westerberg 
4234edf8e2afSMika Westerberg     (void) memset(psinfo, 0, sizeof (*psinfo));
4235edf8e2afSMika Westerberg 
42365f779a3aSIlya Leoshkevich     len = ts->info->env_strings - ts->info->arg_strings;
4237edf8e2afSMika Westerberg     if (len >= ELF_PRARGSZ)
4238edf8e2afSMika Westerberg         len = ELF_PRARGSZ - 1;
42395f779a3aSIlya Leoshkevich     if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_strings, len)) {
4240edf8e2afSMika Westerberg         return -EFAULT;
42415f779a3aSIlya Leoshkevich     }
4242edf8e2afSMika Westerberg     for (i = 0; i < len; i++)
4243edf8e2afSMika Westerberg         if (psinfo->pr_psargs[i] == 0)
4244edf8e2afSMika Westerberg             psinfo->pr_psargs[i] = ' ';
4245edf8e2afSMika Westerberg     psinfo->pr_psargs[len] = 0;
4246edf8e2afSMika Westerberg 
4247edf8e2afSMika Westerberg     psinfo->pr_pid = getpid();
4248edf8e2afSMika Westerberg     psinfo->pr_ppid = getppid();
4249edf8e2afSMika Westerberg     psinfo->pr_pgrp = getpgrp();
4250edf8e2afSMika Westerberg     psinfo->pr_sid = getsid(0);
4251edf8e2afSMika Westerberg     psinfo->pr_uid = getuid();
4252edf8e2afSMika Westerberg     psinfo->pr_gid = getgid();
4253edf8e2afSMika Westerberg 
4254900cfbcaSJim Meyering     base_filename = g_path_get_basename(ts->bprm->filename);
4255900cfbcaSJim Meyering     /*
4256900cfbcaSJim Meyering      * Using strncpy here is fine: at max-length,
4257900cfbcaSJim Meyering      * this field is not NUL-terminated.
4258900cfbcaSJim Meyering      */
4259edf8e2afSMika Westerberg     (void) strncpy(psinfo->pr_fname, base_filename,
4260edf8e2afSMika Westerberg                    sizeof(psinfo->pr_fname));
4261edf8e2afSMika Westerberg 
4262900cfbcaSJim Meyering     g_free(base_filename);
4263edf8e2afSMika Westerberg     bswap_psinfo(psinfo);
4264edf8e2afSMika Westerberg     return (0);
4265edf8e2afSMika Westerberg }
4266edf8e2afSMika Westerberg 
4267edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
4268edf8e2afSMika Westerberg {
4269edf8e2afSMika Westerberg     elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
4270edf8e2afSMika Westerberg     elf_addr_t orig_auxv = auxv;
4271edf8e2afSMika Westerberg     void *ptr;
4272125b0f55SAlexander Graf     int len = ts->info->auxv_len;
4273edf8e2afSMika Westerberg 
4274edf8e2afSMika Westerberg     /*
4275edf8e2afSMika Westerberg      * Auxiliary vector is stored in target process stack.  It contains
4276edf8e2afSMika Westerberg      * {type, value} pairs that we need to dump into note.  This is not
4277edf8e2afSMika Westerberg      * strictly necessary but we do it here for sake of completeness.
4278edf8e2afSMika Westerberg      */
4279edf8e2afSMika Westerberg 
4280edf8e2afSMika Westerberg     /* read in whole auxv vector and copy it to memelfnote */
4281edf8e2afSMika Westerberg     ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
4282edf8e2afSMika Westerberg     if (ptr != NULL) {
4283edf8e2afSMika Westerberg         fill_note(note, "CORE", NT_AUXV, len, ptr);
4284edf8e2afSMika Westerberg         unlock_user(ptr, auxv, len);
4285edf8e2afSMika Westerberg     }
4286edf8e2afSMika Westerberg }
4287edf8e2afSMika Westerberg 
4288edf8e2afSMika Westerberg /*
4289edf8e2afSMika Westerberg  * Constructs name of coredump file.  We have following convention
4290edf8e2afSMika Westerberg  * for the name:
4291edf8e2afSMika Westerberg  *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
4292edf8e2afSMika Westerberg  *
429368af19adSDaniel P. Berrangé  * Returns the filename
4294edf8e2afSMika Westerberg  */
429568af19adSDaniel P. Berrangé static char *core_dump_filename(const TaskState *ts)
4296edf8e2afSMika Westerberg {
429768af19adSDaniel P. Berrangé     g_autoptr(GDateTime) now = g_date_time_new_now_local();
429868af19adSDaniel P. Berrangé     g_autofree char *nowstr = g_date_time_format(now, "%Y%m%d-%H%M%S");
429968af19adSDaniel P. Berrangé     g_autofree char *base_filename = g_path_get_basename(ts->bprm->filename);
4300edf8e2afSMika Westerberg 
430168af19adSDaniel P. Berrangé     return g_strdup_printf("qemu_%s_%s_%d.core",
430268af19adSDaniel P. Berrangé                            base_filename, nowstr, (int)getpid());
4303edf8e2afSMika Westerberg }
4304edf8e2afSMika Westerberg 
4305edf8e2afSMika Westerberg static int dump_write(int fd, const void *ptr, size_t size)
4306edf8e2afSMika Westerberg {
4307edf8e2afSMika Westerberg     const char *bufp = (const char *)ptr;
4308edf8e2afSMika Westerberg     ssize_t bytes_written, bytes_left;
4309edf8e2afSMika Westerberg     struct rlimit dumpsize;
4310edf8e2afSMika Westerberg     off_t pos;
4311edf8e2afSMika Westerberg 
4312edf8e2afSMika Westerberg     bytes_written = 0;
4313edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
4314edf8e2afSMika Westerberg     if ((pos = lseek(fd, 0, SEEK_CUR))==-1) {
4315edf8e2afSMika Westerberg         if (errno == ESPIPE) { /* not a seekable stream */
4316edf8e2afSMika Westerberg             bytes_left = size;
4317edf8e2afSMika Westerberg         } else {
4318edf8e2afSMika Westerberg             return pos;
4319edf8e2afSMika Westerberg         }
4320edf8e2afSMika Westerberg     } else {
4321edf8e2afSMika Westerberg         if (dumpsize.rlim_cur <= pos) {
4322edf8e2afSMika Westerberg             return -1;
4323edf8e2afSMika Westerberg         } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
4324edf8e2afSMika Westerberg             bytes_left = size;
4325edf8e2afSMika Westerberg         } else {
4326edf8e2afSMika Westerberg             size_t limit_left=dumpsize.rlim_cur - pos;
4327edf8e2afSMika Westerberg             bytes_left = limit_left >= size ? size : limit_left ;
4328edf8e2afSMika Westerberg         }
4329edf8e2afSMika Westerberg     }
4330edf8e2afSMika Westerberg 
4331edf8e2afSMika Westerberg     /*
4332edf8e2afSMika Westerberg      * In normal conditions, single write(2) should do but
4333edf8e2afSMika Westerberg      * in case of socket etc. this mechanism is more portable.
4334edf8e2afSMika Westerberg      */
4335edf8e2afSMika Westerberg     do {
4336edf8e2afSMika Westerberg         bytes_written = write(fd, bufp, bytes_left);
4337edf8e2afSMika Westerberg         if (bytes_written < 0) {
4338edf8e2afSMika Westerberg             if (errno == EINTR)
4339edf8e2afSMika Westerberg                 continue;
4340edf8e2afSMika Westerberg             return (-1);
4341edf8e2afSMika Westerberg         } else if (bytes_written == 0) { /* eof */
4342edf8e2afSMika Westerberg             return (-1);
4343edf8e2afSMika Westerberg         }
4344edf8e2afSMika Westerberg         bufp += bytes_written;
4345edf8e2afSMika Westerberg         bytes_left -= bytes_written;
4346edf8e2afSMika Westerberg     } while (bytes_left > 0);
4347edf8e2afSMika Westerberg 
4348edf8e2afSMika Westerberg     return (0);
4349edf8e2afSMika Westerberg }
4350edf8e2afSMika Westerberg 
4351edf8e2afSMika Westerberg static int write_note(struct memelfnote *men, int fd)
4352edf8e2afSMika Westerberg {
4353edf8e2afSMika Westerberg     struct elf_note en;
4354edf8e2afSMika Westerberg 
4355edf8e2afSMika Westerberg     en.n_namesz = men->namesz;
4356edf8e2afSMika Westerberg     en.n_type = men->type;
4357edf8e2afSMika Westerberg     en.n_descsz = men->datasz;
4358edf8e2afSMika Westerberg 
4359edf8e2afSMika Westerberg     bswap_note(&en);
4360edf8e2afSMika Westerberg 
4361edf8e2afSMika Westerberg     if (dump_write(fd, &en, sizeof(en)) != 0)
4362edf8e2afSMika Westerberg         return (-1);
4363edf8e2afSMika Westerberg     if (dump_write(fd, men->name, men->namesz_rounded) != 0)
4364edf8e2afSMika Westerberg         return (-1);
436580f5ce75SLaurent Vivier     if (dump_write(fd, men->data, men->datasz_rounded) != 0)
4366edf8e2afSMika Westerberg         return (-1);
4367edf8e2afSMika Westerberg 
4368edf8e2afSMika Westerberg     return (0);
4369edf8e2afSMika Westerberg }
4370edf8e2afSMika Westerberg 
43719349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *info, const CPUArchState *env)
4372edf8e2afSMika Westerberg {
437329a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
43740429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4375edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4376edf8e2afSMika Westerberg 
43777267c094SAnthony Liguori     ets = g_malloc0(sizeof (*ets));
4378edf8e2afSMika Westerberg     ets->num_notes = 1; /* only prstatus is dumped */
4379edf8e2afSMika Westerberg     fill_prstatus(&ets->prstatus, ts, 0);
4380edf8e2afSMika Westerberg     elf_core_copy_regs(&ets->prstatus.pr_reg, env);
4381edf8e2afSMika Westerberg     fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
4382edf8e2afSMika Westerberg               &ets->prstatus);
4383edf8e2afSMika Westerberg 
438472cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
4385edf8e2afSMika Westerberg 
4386edf8e2afSMika Westerberg     info->notes_size += note_size(&ets->notes[0]);
4387edf8e2afSMika Westerberg }
4388edf8e2afSMika Westerberg 
43896afafa86SPeter Maydell static void init_note_info(struct elf_note_info *info)
43906afafa86SPeter Maydell {
43916afafa86SPeter Maydell     /* Initialize the elf_note_info structure so that it is at
43926afafa86SPeter Maydell      * least safe to call free_note_info() on it. Must be
43936afafa86SPeter Maydell      * called before calling fill_note_info().
43946afafa86SPeter Maydell      */
43956afafa86SPeter Maydell     memset(info, 0, sizeof (*info));
43966afafa86SPeter Maydell     QTAILQ_INIT(&info->thread_list);
43976afafa86SPeter Maydell }
43986afafa86SPeter Maydell 
4399edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *info,
44009349b4f9SAndreas Färber                           long signr, const CPUArchState *env)
4401edf8e2afSMika Westerberg {
4402edf8e2afSMika Westerberg #define NUMNOTES 3
440329a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
44040429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4405edf8e2afSMika Westerberg     int i;
4406edf8e2afSMika Westerberg 
4407c78d65e8SMarkus Armbruster     info->notes = g_new0(struct memelfnote, NUMNOTES);
4408edf8e2afSMika Westerberg     if (info->notes == NULL)
4409edf8e2afSMika Westerberg         return (-ENOMEM);
44107267c094SAnthony Liguori     info->prstatus = g_malloc0(sizeof (*info->prstatus));
4411edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4412edf8e2afSMika Westerberg         return (-ENOMEM);
44137267c094SAnthony Liguori     info->psinfo = g_malloc0(sizeof (*info->psinfo));
4414edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4415edf8e2afSMika Westerberg         return (-ENOMEM);
4416edf8e2afSMika Westerberg 
4417edf8e2afSMika Westerberg     /*
4418edf8e2afSMika Westerberg      * First fill in status (and registers) of current thread
4419edf8e2afSMika Westerberg      * including process info & aux vector.
4420edf8e2afSMika Westerberg      */
4421edf8e2afSMika Westerberg     fill_prstatus(info->prstatus, ts, signr);
4422edf8e2afSMika Westerberg     elf_core_copy_regs(&info->prstatus->pr_reg, env);
4423edf8e2afSMika Westerberg     fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
4424edf8e2afSMika Westerberg               sizeof (*info->prstatus), info->prstatus);
4425edf8e2afSMika Westerberg     fill_psinfo(info->psinfo, ts);
4426edf8e2afSMika Westerberg     fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
4427edf8e2afSMika Westerberg               sizeof (*info->psinfo), info->psinfo);
4428edf8e2afSMika Westerberg     fill_auxv_note(&info->notes[2], ts);
4429edf8e2afSMika Westerberg     info->numnote = 3;
4430edf8e2afSMika Westerberg 
4431edf8e2afSMika Westerberg     info->notes_size = 0;
4432edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4433edf8e2afSMika Westerberg         info->notes_size += note_size(&info->notes[i]);
4434edf8e2afSMika Westerberg 
4435edf8e2afSMika Westerberg     /* read and fill status of all threads */
4436370ed600SJamie Iles     WITH_QEMU_LOCK_GUARD(&qemu_cpu_list_lock) {
4437bdc44640SAndreas Färber         CPU_FOREACH(cpu) {
4438a2247f8eSAndreas Färber             if (cpu == thread_cpu) {
4439edf8e2afSMika Westerberg                 continue;
4440182735efSAndreas Färber             }
4441b77af26eSRichard Henderson             fill_thread_info(info, cpu_env(cpu));
4442edf8e2afSMika Westerberg         }
4443370ed600SJamie Iles     }
4444edf8e2afSMika Westerberg 
4445edf8e2afSMika Westerberg     return (0);
4446edf8e2afSMika Westerberg }
4447edf8e2afSMika Westerberg 
4448edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *info)
4449edf8e2afSMika Westerberg {
4450edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4451edf8e2afSMika Westerberg 
445272cf2d4fSBlue Swirl     while (!QTAILQ_EMPTY(&info->thread_list)) {
445372cf2d4fSBlue Swirl         ets = QTAILQ_FIRST(&info->thread_list);
445472cf2d4fSBlue Swirl         QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
44557267c094SAnthony Liguori         g_free(ets);
4456edf8e2afSMika Westerberg     }
4457edf8e2afSMika Westerberg 
44587267c094SAnthony Liguori     g_free(info->prstatus);
44597267c094SAnthony Liguori     g_free(info->psinfo);
44607267c094SAnthony Liguori     g_free(info->notes);
4461edf8e2afSMika Westerberg }
4462edf8e2afSMika Westerberg 
4463edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *info, int fd)
4464edf8e2afSMika Westerberg {
4465edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4466edf8e2afSMika Westerberg     int i, error = 0;
4467edf8e2afSMika Westerberg 
4468edf8e2afSMika Westerberg     /* write prstatus, psinfo and auxv for current thread */
4469edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4470edf8e2afSMika Westerberg         if ((error = write_note(&info->notes[i], fd)) != 0)
4471edf8e2afSMika Westerberg             return (error);
4472edf8e2afSMika Westerberg 
4473edf8e2afSMika Westerberg     /* write prstatus for each thread */
447452a53afeSEmilio G. Cota     QTAILQ_FOREACH(ets, &info->thread_list, ets_link) {
4475edf8e2afSMika Westerberg         if ((error = write_note(&ets->notes[0], fd)) != 0)
4476edf8e2afSMika Westerberg             return (error);
4477edf8e2afSMika Westerberg     }
4478edf8e2afSMika Westerberg 
4479edf8e2afSMika Westerberg     return (0);
4480edf8e2afSMika Westerberg }
4481edf8e2afSMika Westerberg 
4482edf8e2afSMika Westerberg /*
4483edf8e2afSMika Westerberg  * Write out ELF coredump.
4484edf8e2afSMika Westerberg  *
4485edf8e2afSMika Westerberg  * See documentation of ELF object file format in:
4486edf8e2afSMika Westerberg  * http://www.caldera.com/developers/devspecs/gabi41.pdf
4487edf8e2afSMika Westerberg  *
4488edf8e2afSMika Westerberg  * Coredump format in linux is following:
4489edf8e2afSMika Westerberg  *
4490edf8e2afSMika Westerberg  * 0   +----------------------+         \
4491edf8e2afSMika Westerberg  *     | ELF header           | ET_CORE  |
4492edf8e2afSMika Westerberg  *     +----------------------+          |
4493edf8e2afSMika Westerberg  *     | ELF program headers  |          |--- headers
4494edf8e2afSMika Westerberg  *     | - NOTE section       |          |
4495edf8e2afSMika Westerberg  *     | - PT_LOAD sections   |          |
4496edf8e2afSMika Westerberg  *     +----------------------+         /
4497edf8e2afSMika Westerberg  *     | NOTEs:               |
4498edf8e2afSMika Westerberg  *     | - NT_PRSTATUS        |
4499edf8e2afSMika Westerberg  *     | - NT_PRSINFO         |
4500edf8e2afSMika Westerberg  *     | - NT_AUXV            |
4501edf8e2afSMika Westerberg  *     +----------------------+ <-- aligned to target page
4502edf8e2afSMika Westerberg  *     | Process memory dump  |
4503edf8e2afSMika Westerberg  *     :                      :
4504edf8e2afSMika Westerberg  *     .                      .
4505edf8e2afSMika Westerberg  *     :                      :
4506edf8e2afSMika Westerberg  *     |                      |
4507edf8e2afSMika Westerberg  *     +----------------------+
4508edf8e2afSMika Westerberg  *
4509edf8e2afSMika Westerberg  * NT_PRSTATUS -> struct elf_prstatus (per thread)
4510edf8e2afSMika Westerberg  * NT_PRSINFO  -> struct elf_prpsinfo
4511edf8e2afSMika Westerberg  * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
4512edf8e2afSMika Westerberg  *
4513edf8e2afSMika Westerberg  * Format follows System V format as close as possible.  Current
4514edf8e2afSMika Westerberg  * version limitations are as follows:
4515edf8e2afSMika Westerberg  *     - no floating point registers are dumped
4516edf8e2afSMika Westerberg  *
4517edf8e2afSMika Westerberg  * Function returns 0 in case of success, negative errno otherwise.
4518edf8e2afSMika Westerberg  *
4519edf8e2afSMika Westerberg  * TODO: make this work also during runtime: it should be
4520edf8e2afSMika Westerberg  * possible to force coredump from running process and then
4521edf8e2afSMika Westerberg  * continue processing.  For example qemu could set up SIGUSR2
4522edf8e2afSMika Westerberg  * handler (provided that target process haven't registered
4523edf8e2afSMika Westerberg  * handler for that) that does the dump when signal is received.
4524edf8e2afSMika Westerberg  */
45259349b4f9SAndreas Färber static int elf_core_dump(int signr, const CPUArchState *env)
4526edf8e2afSMika Westerberg {
452729a0af61SRichard Henderson     const CPUState *cpu = env_cpu((CPUArchState *)env);
45280429a971SAndreas Färber     const TaskState *ts = (const TaskState *)cpu->opaque;
4529edf8e2afSMika Westerberg     struct vm_area_struct *vma = NULL;
453068af19adSDaniel P. Berrangé     g_autofree char *corefile = NULL;
4531edf8e2afSMika Westerberg     struct elf_note_info info;
4532edf8e2afSMika Westerberg     struct elfhdr elf;
4533edf8e2afSMika Westerberg     struct elf_phdr phdr;
4534edf8e2afSMika Westerberg     struct rlimit dumpsize;
4535edf8e2afSMika Westerberg     struct mm_struct *mm = NULL;
4536edf8e2afSMika Westerberg     off_t offset = 0, data_offset = 0;
4537edf8e2afSMika Westerberg     int segs = 0;
4538edf8e2afSMika Westerberg     int fd = -1;
4539edf8e2afSMika Westerberg 
45406afafa86SPeter Maydell     init_note_info(&info);
45416afafa86SPeter Maydell 
4542edf8e2afSMika Westerberg     errno = 0;
4543edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
4544edf8e2afSMika Westerberg     if (dumpsize.rlim_cur == 0)
4545edf8e2afSMika Westerberg         return 0;
4546edf8e2afSMika Westerberg 
454768af19adSDaniel P. Berrangé     corefile = core_dump_filename(ts);
4548edf8e2afSMika Westerberg 
4549edf8e2afSMika Westerberg     if ((fd = open(corefile, O_WRONLY | O_CREAT,
4550edf8e2afSMika Westerberg                    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
4551edf8e2afSMika Westerberg         return (-errno);
4552edf8e2afSMika Westerberg 
4553edf8e2afSMika Westerberg     /*
4554edf8e2afSMika Westerberg      * Walk through target process memory mappings and
4555edf8e2afSMika Westerberg      * set up structure containing this information.  After
4556edf8e2afSMika Westerberg      * this point vma_xxx functions can be used.
4557edf8e2afSMika Westerberg      */
4558edf8e2afSMika Westerberg     if ((mm = vma_init()) == NULL)
4559edf8e2afSMika Westerberg         goto out;
4560edf8e2afSMika Westerberg 
4561edf8e2afSMika Westerberg     walk_memory_regions(mm, vma_walker);
4562edf8e2afSMika Westerberg     segs = vma_get_mapping_count(mm);
4563edf8e2afSMika Westerberg 
4564edf8e2afSMika Westerberg     /*
4565edf8e2afSMika Westerberg      * Construct valid coredump ELF header.  We also
4566edf8e2afSMika Westerberg      * add one more segment for notes.
4567edf8e2afSMika Westerberg      */
4568edf8e2afSMika Westerberg     fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
4569edf8e2afSMika Westerberg     if (dump_write(fd, &elf, sizeof (elf)) != 0)
4570edf8e2afSMika Westerberg         goto out;
4571edf8e2afSMika Westerberg 
4572b6af0975SDaniel P. Berrange     /* fill in the in-memory version of notes */
4573edf8e2afSMika Westerberg     if (fill_note_info(&info, signr, env) < 0)
4574edf8e2afSMika Westerberg         goto out;
4575edf8e2afSMika Westerberg 
4576edf8e2afSMika Westerberg     offset += sizeof (elf);                             /* elf header */
4577edf8e2afSMika Westerberg     offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
4578edf8e2afSMika Westerberg 
4579edf8e2afSMika Westerberg     /* write out notes program header */
4580edf8e2afSMika Westerberg     fill_elf_note_phdr(&phdr, info.notes_size, offset);
4581edf8e2afSMika Westerberg 
4582edf8e2afSMika Westerberg     offset += info.notes_size;
4583edf8e2afSMika Westerberg     if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
4584edf8e2afSMika Westerberg         goto out;
4585edf8e2afSMika Westerberg 
4586edf8e2afSMika Westerberg     /*
4587edf8e2afSMika Westerberg      * ELF specification wants data to start at page boundary so
4588edf8e2afSMika Westerberg      * we align it here.
4589edf8e2afSMika Westerberg      */
459080f5ce75SLaurent Vivier     data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
4591edf8e2afSMika Westerberg 
4592edf8e2afSMika Westerberg     /*
4593edf8e2afSMika Westerberg      * Write program headers for memory regions mapped in
4594edf8e2afSMika Westerberg      * the target process.
4595edf8e2afSMika Westerberg      */
4596edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4597edf8e2afSMika Westerberg         (void) memset(&phdr, 0, sizeof (phdr));
4598edf8e2afSMika Westerberg 
4599edf8e2afSMika Westerberg         phdr.p_type = PT_LOAD;
4600edf8e2afSMika Westerberg         phdr.p_offset = offset;
4601edf8e2afSMika Westerberg         phdr.p_vaddr = vma->vma_start;
4602edf8e2afSMika Westerberg         phdr.p_paddr = 0;
4603edf8e2afSMika Westerberg         phdr.p_filesz = vma_dump_size(vma);
4604edf8e2afSMika Westerberg         offset += phdr.p_filesz;
4605edf8e2afSMika Westerberg         phdr.p_memsz = vma->vma_end - vma->vma_start;
4606edf8e2afSMika Westerberg         phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
4607edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_WRITE)
4608edf8e2afSMika Westerberg             phdr.p_flags |= PF_W;
4609edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_EXEC)
4610edf8e2afSMika Westerberg             phdr.p_flags |= PF_X;
4611edf8e2afSMika Westerberg         phdr.p_align = ELF_EXEC_PAGESIZE;
4612edf8e2afSMika Westerberg 
461380f5ce75SLaurent Vivier         bswap_phdr(&phdr, 1);
4614772034b6SPeter Maydell         if (dump_write(fd, &phdr, sizeof(phdr)) != 0) {
4615772034b6SPeter Maydell             goto out;
4616772034b6SPeter Maydell         }
4617edf8e2afSMika Westerberg     }
4618edf8e2afSMika Westerberg 
4619edf8e2afSMika Westerberg     /*
4620edf8e2afSMika Westerberg      * Next we write notes just after program headers.  No
4621edf8e2afSMika Westerberg      * alignment needed here.
4622edf8e2afSMika Westerberg      */
4623edf8e2afSMika Westerberg     if (write_note_info(&info, fd) < 0)
4624edf8e2afSMika Westerberg         goto out;
4625edf8e2afSMika Westerberg 
4626edf8e2afSMika Westerberg     /* align data to page boundary */
4627edf8e2afSMika Westerberg     if (lseek(fd, data_offset, SEEK_SET) != data_offset)
4628edf8e2afSMika Westerberg         goto out;
4629edf8e2afSMika Westerberg 
4630edf8e2afSMika Westerberg     /*
4631edf8e2afSMika Westerberg      * Finally we can dump process memory into corefile as well.
4632edf8e2afSMika Westerberg      */
4633edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4634edf8e2afSMika Westerberg         abi_ulong addr;
4635edf8e2afSMika Westerberg         abi_ulong end;
4636edf8e2afSMika Westerberg 
4637edf8e2afSMika Westerberg         end = vma->vma_start + vma_dump_size(vma);
4638edf8e2afSMika Westerberg 
4639edf8e2afSMika Westerberg         for (addr = vma->vma_start; addr < end;
4640edf8e2afSMika Westerberg              addr += TARGET_PAGE_SIZE) {
4641edf8e2afSMika Westerberg             char page[TARGET_PAGE_SIZE];
4642edf8e2afSMika Westerberg             int error;
4643edf8e2afSMika Westerberg 
4644edf8e2afSMika Westerberg             /*
4645edf8e2afSMika Westerberg              *  Read in page from target process memory and
4646edf8e2afSMika Westerberg              *  write it to coredump file.
4647edf8e2afSMika Westerberg              */
4648edf8e2afSMika Westerberg             error = copy_from_user(page, addr, sizeof (page));
4649edf8e2afSMika Westerberg             if (error != 0) {
465049995e17SAurelien Jarno                 (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
4651edf8e2afSMika Westerberg                                addr);
4652edf8e2afSMika Westerberg                 errno = -error;
4653edf8e2afSMika Westerberg                 goto out;
4654edf8e2afSMika Westerberg             }
4655edf8e2afSMika Westerberg             if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
4656edf8e2afSMika Westerberg                 goto out;
4657edf8e2afSMika Westerberg         }
4658edf8e2afSMika Westerberg     }
4659edf8e2afSMika Westerberg 
4660edf8e2afSMika Westerberg  out:
4661edf8e2afSMika Westerberg     free_note_info(&info);
4662edf8e2afSMika Westerberg     if (mm != NULL)
4663edf8e2afSMika Westerberg         vma_delete(mm);
4664edf8e2afSMika Westerberg     (void) close(fd);
4665edf8e2afSMika Westerberg 
4666edf8e2afSMika Westerberg     if (errno != 0)
4667edf8e2afSMika Westerberg         return (-errno);
4668edf8e2afSMika Westerberg     return (0);
4669edf8e2afSMika Westerberg }
4670edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
4671edf8e2afSMika Westerberg 
4672e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
4673e5fe0c52Spbrook {
4674e5fe0c52Spbrook     init_thread(regs, infop);
4675e5fe0c52Spbrook }
4676