xref: /openbmc/qemu/linux-user/elfload.c (revision 86cf82dc9fa366d6758f4b1f9587c8d2f6062bad)
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 */
2204*86cf82dcSRichard Henderson static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
2205*86cf82dcSRichard Henderson                          abi_ulong load_bias);
2206edf8e2afSMika Westerberg 
22079058abddSRichard Henderson /* Verify the portions of EHDR within E_IDENT for the target.
22089058abddSRichard Henderson    This can be performed before bswapping the entire header.  */
22099058abddSRichard Henderson static bool elf_check_ident(struct elfhdr *ehdr)
22109058abddSRichard Henderson {
22119058abddSRichard Henderson     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
22129058abddSRichard Henderson             && ehdr->e_ident[EI_MAG1] == ELFMAG1
22139058abddSRichard Henderson             && ehdr->e_ident[EI_MAG2] == ELFMAG2
22149058abddSRichard Henderson             && ehdr->e_ident[EI_MAG3] == ELFMAG3
22159058abddSRichard Henderson             && ehdr->e_ident[EI_CLASS] == ELF_CLASS
22169058abddSRichard Henderson             && ehdr->e_ident[EI_DATA] == ELF_DATA
22179058abddSRichard Henderson             && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
22189058abddSRichard Henderson }
22199058abddSRichard Henderson 
22209058abddSRichard Henderson /* Verify the portions of EHDR outside of E_IDENT for the target.
22219058abddSRichard Henderson    This has to wait until after bswapping the header.  */
22229058abddSRichard Henderson static bool elf_check_ehdr(struct elfhdr *ehdr)
22239058abddSRichard Henderson {
22249058abddSRichard Henderson     return (elf_check_arch(ehdr->e_machine)
2225ace3d654SCarlo Marcelo Arenas Belón             && elf_check_abi(ehdr->e_flags)
22269058abddSRichard Henderson             && ehdr->e_ehsize == sizeof(struct elfhdr)
22279058abddSRichard Henderson             && ehdr->e_phentsize == sizeof(struct elf_phdr)
22289058abddSRichard Henderson             && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
22299058abddSRichard Henderson }
22309058abddSRichard Henderson 
223131e31b8aSbellard /*
2232e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
223331e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
223431e31b8aSbellard  * to be put directly into the top of new user memory.
223531e31b8aSbellard  *
223631e31b8aSbellard  */
223759baae9aSStefan Brüns static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch,
223859baae9aSStefan Brüns                                   abi_ulong p, abi_ulong stack_limit)
223931e31b8aSbellard {
224059baae9aSStefan Brüns     char *tmp;
22417c4ee5bcSRichard Henderson     int len, i;
224259baae9aSStefan Brüns     abi_ulong top = p;
224331e31b8aSbellard 
224431e31b8aSbellard     if (!p) {
224531e31b8aSbellard         return 0;       /* bullet-proofing */
224631e31b8aSbellard     }
224759baae9aSStefan Brüns 
22487c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
22497c4ee5bcSRichard Henderson         int offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
22507c4ee5bcSRichard Henderson         for (i = argc - 1; i >= 0; --i) {
22517c4ee5bcSRichard Henderson             tmp = argv[i];
2252edf779ffSbellard             if (!tmp) {
225331e31b8aSbellard                 fprintf(stderr, "VFS: argc is wrong");
225431e31b8aSbellard                 exit(-1);
225531e31b8aSbellard             }
225659baae9aSStefan Brüns             len = strlen(tmp) + 1;
225759baae9aSStefan Brüns             tmp += len;
225859baae9aSStefan Brüns 
225959baae9aSStefan Brüns             if (len > (p - stack_limit)) {
226031e31b8aSbellard                 return 0;
226131e31b8aSbellard             }
226231e31b8aSbellard             while (len) {
226331e31b8aSbellard                 int bytes_to_copy = (len > offset) ? offset : len;
226431e31b8aSbellard                 tmp -= bytes_to_copy;
226531e31b8aSbellard                 p -= bytes_to_copy;
226631e31b8aSbellard                 offset -= bytes_to_copy;
226731e31b8aSbellard                 len -= bytes_to_copy;
226859baae9aSStefan Brüns 
226959baae9aSStefan Brüns                 memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
227059baae9aSStefan Brüns 
227159baae9aSStefan Brüns                 if (offset == 0) {
227259baae9aSStefan Brüns                     memcpy_to_target(p, scratch, top - p);
227359baae9aSStefan Brüns                     top = p;
227459baae9aSStefan Brüns                     offset = TARGET_PAGE_SIZE;
227531e31b8aSbellard                 }
227631e31b8aSbellard             }
227731e31b8aSbellard         }
22787c4ee5bcSRichard Henderson         if (p != top) {
227959baae9aSStefan Brüns             memcpy_to_target(p, scratch + offset, top - p);
228059baae9aSStefan Brüns         }
22817c4ee5bcSRichard Henderson     } else {
22827c4ee5bcSRichard Henderson         int remaining = TARGET_PAGE_SIZE - (p % TARGET_PAGE_SIZE);
22837c4ee5bcSRichard Henderson         for (i = 0; i < argc; ++i) {
22847c4ee5bcSRichard Henderson             tmp = argv[i];
22857c4ee5bcSRichard Henderson             if (!tmp) {
22867c4ee5bcSRichard Henderson                 fprintf(stderr, "VFS: argc is wrong");
22877c4ee5bcSRichard Henderson                 exit(-1);
22887c4ee5bcSRichard Henderson             }
22897c4ee5bcSRichard Henderson             len = strlen(tmp) + 1;
22907c4ee5bcSRichard Henderson             if (len > (stack_limit - p)) {
22917c4ee5bcSRichard Henderson                 return 0;
22927c4ee5bcSRichard Henderson             }
22937c4ee5bcSRichard Henderson             while (len) {
22947c4ee5bcSRichard Henderson                 int bytes_to_copy = (len > remaining) ? remaining : len;
22957c4ee5bcSRichard Henderson 
22967c4ee5bcSRichard Henderson                 memcpy_fromfs(scratch + (p - top), tmp, bytes_to_copy);
22977c4ee5bcSRichard Henderson 
22987c4ee5bcSRichard Henderson                 tmp += bytes_to_copy;
22997c4ee5bcSRichard Henderson                 remaining -= bytes_to_copy;
23007c4ee5bcSRichard Henderson                 p += bytes_to_copy;
23017c4ee5bcSRichard Henderson                 len -= bytes_to_copy;
23027c4ee5bcSRichard Henderson 
23037c4ee5bcSRichard Henderson                 if (remaining == 0) {
23047c4ee5bcSRichard Henderson                     memcpy_to_target(top, scratch, p - top);
23057c4ee5bcSRichard Henderson                     top = p;
23067c4ee5bcSRichard Henderson                     remaining = TARGET_PAGE_SIZE;
23077c4ee5bcSRichard Henderson                 }
23087c4ee5bcSRichard Henderson             }
23097c4ee5bcSRichard Henderson         }
23107c4ee5bcSRichard Henderson         if (p != top) {
23117c4ee5bcSRichard Henderson             memcpy_to_target(top, scratch, p - top);
23127c4ee5bcSRichard Henderson         }
23137c4ee5bcSRichard Henderson     }
231459baae9aSStefan Brüns 
231531e31b8aSbellard     return p;
231631e31b8aSbellard }
231731e31b8aSbellard 
231859baae9aSStefan Brüns /* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of
231959baae9aSStefan Brüns  * argument/environment space. Newer kernels (>2.6.33) allow more,
232059baae9aSStefan Brüns  * dependent on stack size, but guarantee at least 32 pages for
232159baae9aSStefan Brüns  * backwards compatibility.
232259baae9aSStefan Brüns  */
232359baae9aSStefan Brüns #define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE)
232459baae9aSStefan Brüns 
232559baae9aSStefan Brüns static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
232631e31b8aSbellard                                  struct image_info *info)
232731e31b8aSbellard {
232859baae9aSStefan Brüns     abi_ulong size, error, guard;
2329872f3d04SRichard Henderson     int prot;
233031e31b8aSbellard 
2331703e0e89SRichard Henderson     size = guest_stack_size;
233259baae9aSStefan Brüns     if (size < STACK_LOWER_LIMIT) {
233359baae9aSStefan Brüns         size = STACK_LOWER_LIMIT;
233460dcbcb5SRichard Henderson     }
2335f4388205SHelge Deller 
2336f4388205SHelge Deller     if (STACK_GROWS_DOWN) {
233760dcbcb5SRichard Henderson         guard = TARGET_PAGE_SIZE;
23388e3b0cbbSMarc-André Lureau         if (guard < qemu_real_host_page_size()) {
23398e3b0cbbSMarc-André Lureau             guard = qemu_real_host_page_size();
234060dcbcb5SRichard Henderson         }
2341f4388205SHelge Deller     } else {
2342f4388205SHelge Deller         /* no guard page for hppa target where stack grows upwards. */
2343f4388205SHelge Deller         guard = 0;
2344f4388205SHelge Deller     }
234560dcbcb5SRichard Henderson 
2346872f3d04SRichard Henderson     prot = PROT_READ | PROT_WRITE;
2347872f3d04SRichard Henderson     if (info->exec_stack) {
2348872f3d04SRichard Henderson         prot |= PROT_EXEC;
2349872f3d04SRichard Henderson     }
2350872f3d04SRichard Henderson     error = target_mmap(0, size + guard, prot,
235160dcbcb5SRichard Henderson                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
235209bfb054Sbellard     if (error == -1) {
235360dcbcb5SRichard Henderson         perror("mmap stack");
235431e31b8aSbellard         exit(-1);
235531e31b8aSbellard     }
235631e31b8aSbellard 
235760dcbcb5SRichard Henderson     /* We reserve one extra page at the top of the stack as guard.  */
23587c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
235960dcbcb5SRichard Henderson         target_mprotect(error, guard, PROT_NONE);
236060dcbcb5SRichard Henderson         info->stack_limit = error + guard;
236159baae9aSStefan Brüns         return info->stack_limit + size - sizeof(void *);
23627c4ee5bcSRichard Henderson     } else {
23637c4ee5bcSRichard Henderson         info->stack_limit = error + size;
23647c4ee5bcSRichard Henderson         return error;
23657c4ee5bcSRichard Henderson     }
236631e31b8aSbellard }
236731e31b8aSbellard 
23682d385be6SRichard Henderson /**
23692d385be6SRichard Henderson  * zero_bss:
23702d385be6SRichard Henderson  *
23712d385be6SRichard Henderson  * Map and zero the bss.  We need to explicitly zero any fractional pages
23722d385be6SRichard Henderson  * after the data section (i.e. bss).  Return false on mapping failure.
23732d385be6SRichard Henderson  */
2374e6e66b03SRichard Henderson static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss,
2375e6e66b03SRichard Henderson                      int prot, Error **errp)
237631e31b8aSbellard {
23772d385be6SRichard Henderson     abi_ulong align_bss;
2378cf129f3aSRichard Henderson 
2379e6e66b03SRichard Henderson     /* We only expect writable bss; the code segment shouldn't need this. */
2380e6e66b03SRichard Henderson     if (!(prot & PROT_WRITE)) {
2381e6e66b03SRichard Henderson         error_setg(errp, "PT_LOAD with non-writable bss");
2382e6e66b03SRichard Henderson         return false;
2383e6e66b03SRichard Henderson     }
2384e6e66b03SRichard Henderson 
23852d385be6SRichard Henderson     align_bss = TARGET_PAGE_ALIGN(start_bss);
23862d385be6SRichard Henderson     end_bss = TARGET_PAGE_ALIGN(end_bss);
2387cf129f3aSRichard Henderson 
23882d385be6SRichard Henderson     if (start_bss < align_bss) {
23892d385be6SRichard Henderson         int flags = page_get_flags(start_bss);
2390cf129f3aSRichard Henderson 
2391e6e66b03SRichard Henderson         if (!(flags & PAGE_BITS)) {
2392e6e66b03SRichard Henderson             /*
2393e6e66b03SRichard Henderson              * The whole address space of the executable was reserved
2394e6e66b03SRichard Henderson              * at the start, therefore all pages will be VALID.
2395e6e66b03SRichard Henderson              * But assuming there are no PROT_NONE PT_LOAD segments,
2396e6e66b03SRichard Henderson              * a PROT_NONE page means no data all bss, and we can
2397e6e66b03SRichard Henderson              * simply extend the new anon mapping back to the start
2398e6e66b03SRichard Henderson              * of the page of bss.
2399e6e66b03SRichard Henderson              */
24002d385be6SRichard Henderson             align_bss -= TARGET_PAGE_SIZE;
24012d385be6SRichard Henderson         } else {
2402e6e66b03SRichard Henderson             /*
2403e6e66b03SRichard Henderson              * The start of the bss shares a page with something.
2404e6e66b03SRichard Henderson              * The only thing that we expect is the data section,
2405e6e66b03SRichard Henderson              * which would already be marked writable.
2406e6e66b03SRichard Henderson              * Overlapping the RX code segment seems malformed.
2407e6e66b03SRichard Henderson              */
2408e6e66b03SRichard Henderson             if (!(flags & PAGE_WRITE)) {
2409e6e66b03SRichard Henderson                 error_setg(errp, "PT_LOAD with bss overlapping "
2410e6e66b03SRichard Henderson                            "non-writable page");
2411e6e66b03SRichard Henderson                 return false;
2412e6e66b03SRichard Henderson             }
2413e6e66b03SRichard Henderson 
2414e6e66b03SRichard Henderson             /* The page is already mapped and writable. */
2415e6e66b03SRichard Henderson             memset(g2h_untagged(start_bss), 0, align_bss - start_bss);
241631e31b8aSbellard         }
2417f46e9a0bSTom Musta     }
2418cf129f3aSRichard Henderson 
2419e6e66b03SRichard Henderson     if (align_bss < end_bss &&
24202d385be6SRichard Henderson         target_mmap(align_bss, end_bss - align_bss, prot,
2421e6e66b03SRichard Henderson                     MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) {
2422e6e66b03SRichard Henderson         error_setg_errno(errp, errno, "Error mapping bss");
2423e6e66b03SRichard Henderson         return false;
2424e6e66b03SRichard Henderson     }
2425e6e66b03SRichard Henderson     return true;
2426853d6f7aSbellard }
2427853d6f7aSbellard 
2428d2796be6SMax Filippov #if defined(TARGET_ARM)
2429cf58affeSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2430cf58affeSChristophe Lyon {
2431cf58affeSChristophe Lyon     return exec->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC;
2432cf58affeSChristophe Lyon }
2433d2796be6SMax Filippov #elif defined(TARGET_XTENSA)
2434d2796be6SMax Filippov static int elf_is_fdpic(struct elfhdr *exec)
2435d2796be6SMax Filippov {
2436d2796be6SMax Filippov     return exec->e_ident[EI_OSABI] == ELFOSABI_XTENSA_FDPIC;
2437d2796be6SMax Filippov }
2438cf58affeSChristophe Lyon #else
2439a99856cdSChristophe Lyon /* Default implementation, always false.  */
2440a99856cdSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2441a99856cdSChristophe Lyon {
2442a99856cdSChristophe Lyon     return 0;
2443a99856cdSChristophe Lyon }
2444cf58affeSChristophe Lyon #endif
2445a99856cdSChristophe Lyon 
24461af02e83SMike Frysinger static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
24471af02e83SMike Frysinger {
24481af02e83SMike Frysinger     uint16_t n;
24491af02e83SMike Frysinger     struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
24501af02e83SMike Frysinger 
24511af02e83SMike Frysinger     /* elf32_fdpic_loadseg */
24521af02e83SMike Frysinger     n = info->nsegs;
24531af02e83SMike Frysinger     while (n--) {
24541af02e83SMike Frysinger         sp -= 12;
24551af02e83SMike Frysinger         put_user_u32(loadsegs[n].addr, sp+0);
24561af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_vaddr, sp+4);
24571af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_memsz, sp+8);
24581af02e83SMike Frysinger     }
24591af02e83SMike Frysinger 
24601af02e83SMike Frysinger     /* elf32_fdpic_loadmap */
24611af02e83SMike Frysinger     sp -= 4;
24621af02e83SMike Frysinger     put_user_u16(0, sp+0); /* version */
24631af02e83SMike Frysinger     put_user_u16(info->nsegs, sp+2); /* nsegs */
24641af02e83SMike Frysinger 
24651af02e83SMike Frysinger     info->personality = PER_LINUX_FDPIC;
24661af02e83SMike Frysinger     info->loadmap_addr = sp;
24671af02e83SMike Frysinger 
24681af02e83SMike Frysinger     return sp;
24691af02e83SMike Frysinger }
24701af02e83SMike Frysinger 
2471992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
247231e31b8aSbellard                                    struct elfhdr *exec,
24738e62a717SRichard Henderson                                    struct image_info *info,
24748e62a717SRichard Henderson                                    struct image_info *interp_info)
247531e31b8aSbellard {
2476992f48a0Sblueswir1     abi_ulong sp;
24777c4ee5bcSRichard Henderson     abi_ulong u_argc, u_argv, u_envp, u_auxv;
247853a5960aSpbrook     int size;
247914322badSLaurent ALFONSI     int i;
248014322badSLaurent ALFONSI     abi_ulong u_rand_bytes;
248114322badSLaurent ALFONSI     uint8_t k_rand_bytes[16];
2482fcdc0ab4SJiaxun Yang     abi_ulong u_platform, u_base_platform;
2483fcdc0ab4SJiaxun Yang     const char *k_platform, *k_base_platform;
2484863cf0b7Sj_mayer     const int n = sizeof(elf_addr_t);
248531e31b8aSbellard 
248653a5960aSpbrook     sp = p;
24871af02e83SMike Frysinger 
24881af02e83SMike Frysinger     /* Needs to be before we load the env/argc/... */
24891af02e83SMike Frysinger     if (elf_is_fdpic(exec)) {
24901af02e83SMike Frysinger         /* Need 4 byte alignment for these structs */
24911af02e83SMike Frysinger         sp &= ~3;
24921af02e83SMike Frysinger         sp = loader_build_fdpic_loadmap(info, sp);
24931af02e83SMike Frysinger         info->other_info = interp_info;
24941af02e83SMike Frysinger         if (interp_info) {
24951af02e83SMike Frysinger             interp_info->other_info = info;
24961af02e83SMike Frysinger             sp = loader_build_fdpic_loadmap(interp_info, sp);
24973cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = interp_info->loadmap_addr;
24983cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = interp_info->pt_dynamic_addr;
24993cb10cfaSChristophe Lyon         } else {
25003cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = 0;
25013cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = 0;
25021af02e83SMike Frysinger         }
25031af02e83SMike Frysinger     }
25041af02e83SMike Frysinger 
2505fcdc0ab4SJiaxun Yang     u_base_platform = 0;
2506fcdc0ab4SJiaxun Yang     k_base_platform = ELF_BASE_PLATFORM;
2507fcdc0ab4SJiaxun Yang     if (k_base_platform) {
2508fcdc0ab4SJiaxun Yang         size_t len = strlen(k_base_platform) + 1;
2509fcdc0ab4SJiaxun Yang         if (STACK_GROWS_DOWN) {
2510fcdc0ab4SJiaxun Yang             sp -= (len + n - 1) & ~(n - 1);
2511fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2512fcdc0ab4SJiaxun Yang             /* FIXME - check return value of memcpy_to_target() for failure */
2513fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2514fcdc0ab4SJiaxun Yang         } else {
2515fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2516fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2517fcdc0ab4SJiaxun Yang             sp += len + 1;
2518fcdc0ab4SJiaxun Yang         }
2519fcdc0ab4SJiaxun Yang     }
2520fcdc0ab4SJiaxun Yang 
252153a5960aSpbrook     u_platform = 0;
252215338fd7Sbellard     k_platform = ELF_PLATFORM;
252315338fd7Sbellard     if (k_platform) {
252415338fd7Sbellard         size_t len = strlen(k_platform) + 1;
25257c4ee5bcSRichard Henderson         if (STACK_GROWS_DOWN) {
252653a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
252753a5960aSpbrook             u_platform = sp;
2528579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
252953a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
25307c4ee5bcSRichard Henderson         } else {
25317c4ee5bcSRichard Henderson             memcpy_to_target(sp, k_platform, len);
25327c4ee5bcSRichard Henderson             u_platform = sp;
25337c4ee5bcSRichard Henderson             sp += len + 1;
25347c4ee5bcSRichard Henderson         }
25357c4ee5bcSRichard Henderson     }
25367c4ee5bcSRichard Henderson 
25377c4ee5bcSRichard Henderson     /* Provide 16 byte alignment for the PRNG, and basic alignment for
25387c4ee5bcSRichard Henderson      * the argv and envp pointers.
25397c4ee5bcSRichard Henderson      */
25407c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
25417c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_DOWN(sp, 16);
25427c4ee5bcSRichard Henderson     } else {
25437c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp, 16);
254415338fd7Sbellard     }
254514322badSLaurent ALFONSI 
254614322badSLaurent ALFONSI     /*
2547c6a2377fSRichard Henderson      * Generate 16 random bytes for userspace PRNG seeding.
254814322badSLaurent ALFONSI      */
2549c6a2377fSRichard Henderson     qemu_guest_getrandom_nofail(k_rand_bytes, sizeof(k_rand_bytes));
25507c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
255114322badSLaurent ALFONSI         sp -= 16;
255214322badSLaurent ALFONSI         u_rand_bytes = sp;
255314322badSLaurent ALFONSI         /* FIXME - check return value of memcpy_to_target() for failure */
255414322badSLaurent ALFONSI         memcpy_to_target(sp, k_rand_bytes, 16);
25557c4ee5bcSRichard Henderson     } else {
25567c4ee5bcSRichard Henderson         memcpy_to_target(sp, k_rand_bytes, 16);
25577c4ee5bcSRichard Henderson         u_rand_bytes = sp;
25587c4ee5bcSRichard Henderson         sp += 16;
25597c4ee5bcSRichard Henderson     }
256014322badSLaurent ALFONSI 
256153a5960aSpbrook     size = (DLINFO_ITEMS + 1) * 2;
2562fcdc0ab4SJiaxun Yang     if (k_base_platform)
2563fcdc0ab4SJiaxun Yang         size += 2;
256415338fd7Sbellard     if (k_platform)
256553a5960aSpbrook         size += 2;
2566f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
256753a5960aSpbrook     size += DLINFO_ARCH_ITEMS * 2;
2568f5155289Sbellard #endif
2569ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2570ad6919dcSPeter Maydell     size += 2;
2571ad6919dcSPeter Maydell #endif
2572f516511eSPeter Maydell     info->auxv_len = size * n;
2573f516511eSPeter Maydell 
257453a5960aSpbrook     size += envc + argc + 2;
2575b9329d4bSRichard Henderson     size += 1;  /* argc itself */
257653a5960aSpbrook     size *= n;
25777c4ee5bcSRichard Henderson 
25787c4ee5bcSRichard Henderson     /* Allocate space and finalize stack alignment for entry now.  */
25797c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
25807c4ee5bcSRichard Henderson         u_argc = QEMU_ALIGN_DOWN(sp - size, STACK_ALIGNMENT);
25817c4ee5bcSRichard Henderson         sp = u_argc;
25827c4ee5bcSRichard Henderson     } else {
25837c4ee5bcSRichard Henderson         u_argc = sp;
25847c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp + size, STACK_ALIGNMENT);
25857c4ee5bcSRichard Henderson     }
25867c4ee5bcSRichard Henderson 
25877c4ee5bcSRichard Henderson     u_argv = u_argc + n;
25887c4ee5bcSRichard Henderson     u_envp = u_argv + (argc + 1) * n;
25897c4ee5bcSRichard Henderson     u_auxv = u_envp + (envc + 1) * n;
25907c4ee5bcSRichard Henderson     info->saved_auxv = u_auxv;
259160f1c801SRichard Henderson     info->argc = argc;
259260f1c801SRichard Henderson     info->envc = envc;
259360f1c801SRichard Henderson     info->argv = u_argv;
259460f1c801SRichard Henderson     info->envp = u_envp;
2595f5155289Sbellard 
2596863cf0b7Sj_mayer     /* This is correct because Linux defines
2597863cf0b7Sj_mayer      * elf_addr_t as Elf32_Off / Elf64_Off
2598863cf0b7Sj_mayer      */
259953a5960aSpbrook #define NEW_AUX_ENT(id, val) do {               \
26007c4ee5bcSRichard Henderson         put_user_ual(id, u_auxv);  u_auxv += n; \
26017c4ee5bcSRichard Henderson         put_user_ual(val, u_auxv); u_auxv += n; \
260253a5960aSpbrook     } while(0)
26032f619698Sbellard 
260482991bedSPeter Maydell #ifdef ARCH_DLINFO
260582991bedSPeter Maydell     /*
260682991bedSPeter Maydell      * ARCH_DLINFO must come first so platform specific code can enforce
260782991bedSPeter Maydell      * special alignment requirements on the AUXV if necessary (eg. PPC).
260882991bedSPeter Maydell      */
260982991bedSPeter Maydell     ARCH_DLINFO;
261082991bedSPeter Maydell #endif
2611f516511eSPeter Maydell     /* There must be exactly DLINFO_ITEMS entries here, or the assert
2612f516511eSPeter Maydell      * on info->auxv_len will trigger.
2613f516511eSPeter Maydell      */
26148e62a717SRichard Henderson     NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
2615992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
2616992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
261733143c44SLaurent Vivier     if ((info->alignment & ~qemu_host_page_mask) != 0) {
261833143c44SLaurent Vivier         /* Target doesn't support host page size alignment */
261933143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
262033143c44SLaurent Vivier     } else {
262133143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(MAX(TARGET_PAGE_SIZE,
262233143c44SLaurent Vivier                                                qemu_host_page_size)));
262333143c44SLaurent Vivier     }
26248e62a717SRichard Henderson     NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
2625992f48a0Sblueswir1     NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
26268e62a717SRichard Henderson     NEW_AUX_ENT(AT_ENTRY, info->entry);
2627992f48a0Sblueswir1     NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
2628992f48a0Sblueswir1     NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
2629992f48a0Sblueswir1     NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
2630992f48a0Sblueswir1     NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
2631992f48a0Sblueswir1     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
2632a07c67dfSpbrook     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
263314322badSLaurent ALFONSI     NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
2634444cd5c3SMarco A L Barbosa     NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
2635e0d1673dSLirong Yuan     NEW_AUX_ENT(AT_EXECFN, info->file_string);
263614322badSLaurent ALFONSI 
2637ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2638ad6919dcSPeter Maydell     NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
2639ad6919dcSPeter Maydell #endif
2640ad6919dcSPeter Maydell 
2641fcdc0ab4SJiaxun Yang     if (u_base_platform) {
2642fcdc0ab4SJiaxun Yang         NEW_AUX_ENT(AT_BASE_PLATFORM, u_base_platform);
2643fcdc0ab4SJiaxun Yang     }
26447c4ee5bcSRichard Henderson     if (u_platform) {
264553a5960aSpbrook         NEW_AUX_ENT(AT_PLATFORM, u_platform);
26467c4ee5bcSRichard Henderson     }
26477c4ee5bcSRichard Henderson     NEW_AUX_ENT (AT_NULL, 0);
2648f5155289Sbellard #undef NEW_AUX_ENT
2649f5155289Sbellard 
2650f516511eSPeter Maydell     /* Check that our initial calculation of the auxv length matches how much
2651f516511eSPeter Maydell      * we actually put into it.
2652f516511eSPeter Maydell      */
2653f516511eSPeter Maydell     assert(info->auxv_len == u_auxv - info->saved_auxv);
2654edf8e2afSMika Westerberg 
26557c4ee5bcSRichard Henderson     put_user_ual(argc, u_argc);
26567c4ee5bcSRichard Henderson 
26577c4ee5bcSRichard Henderson     p = info->arg_strings;
26587c4ee5bcSRichard Henderson     for (i = 0; i < argc; ++i) {
26597c4ee5bcSRichard Henderson         put_user_ual(p, u_argv);
26607c4ee5bcSRichard Henderson         u_argv += n;
26617c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
26627c4ee5bcSRichard Henderson     }
26637c4ee5bcSRichard Henderson     put_user_ual(0, u_argv);
26647c4ee5bcSRichard Henderson 
26657c4ee5bcSRichard Henderson     p = info->env_strings;
26667c4ee5bcSRichard Henderson     for (i = 0; i < envc; ++i) {
26677c4ee5bcSRichard Henderson         put_user_ual(p, u_envp);
26687c4ee5bcSRichard Henderson         u_envp += n;
26697c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
26707c4ee5bcSRichard Henderson     }
26717c4ee5bcSRichard Henderson     put_user_ual(0, u_envp);
26727c4ee5bcSRichard Henderson 
267331e31b8aSbellard     return sp;
267431e31b8aSbellard }
267531e31b8aSbellard 
2676f5ef0e51SRichard Henderson #if defined(HI_COMMPAGE)
2677eee816c0SRichard Henderson #define LO_COMMPAGE -1
2678f5ef0e51SRichard Henderson #elif defined(LO_COMMPAGE)
267966346fafSRichard Henderson #define HI_COMMPAGE 0
2680f5ef0e51SRichard Henderson #else
2681f5ef0e51SRichard Henderson #define HI_COMMPAGE 0
2682eee816c0SRichard Henderson #define LO_COMMPAGE -1
2683d461b73eSRichard Henderson #ifndef INIT_GUEST_COMMPAGE
2684ee947430SAlex Bennée #define init_guest_commpage() true
2685ee947430SAlex Bennée #endif
2686d461b73eSRichard Henderson #endif
2687ee947430SAlex Bennée 
268806f38c66SRichard Henderson /**
268906f38c66SRichard Henderson  * pgb_try_mmap:
269006f38c66SRichard Henderson  * @addr: host start address
269106f38c66SRichard Henderson  * @addr_last: host last address
269206f38c66SRichard Henderson  * @keep: do not unmap the probe region
269306f38c66SRichard Henderson  *
269406f38c66SRichard Henderson  * Return 1 if [@addr, @addr_last] is not mapped in the host,
269506f38c66SRichard Henderson  * return 0 if it is not available to map, and -1 on mmap error.
269606f38c66SRichard Henderson  * If @keep, the region is left mapped on success, otherwise unmapped.
269706f38c66SRichard Henderson  */
269806f38c66SRichard Henderson static int pgb_try_mmap(uintptr_t addr, uintptr_t addr_last, bool keep)
269906f38c66SRichard Henderson {
270006f38c66SRichard Henderson     size_t size = addr_last - addr + 1;
270106f38c66SRichard Henderson     void *p = mmap((void *)addr, size, PROT_NONE,
270206f38c66SRichard Henderson                    MAP_ANONYMOUS | MAP_PRIVATE |
270306f38c66SRichard Henderson                    MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
270406f38c66SRichard Henderson     int ret;
270506f38c66SRichard Henderson 
270606f38c66SRichard Henderson     if (p == MAP_FAILED) {
270706f38c66SRichard Henderson         return errno == EEXIST ? 0 : -1;
270806f38c66SRichard Henderson     }
270906f38c66SRichard Henderson     ret = p == (void *)addr;
271006f38c66SRichard Henderson     if (!keep || !ret) {
271106f38c66SRichard Henderson         munmap(p, size);
271206f38c66SRichard Henderson     }
271306f38c66SRichard Henderson     return ret;
271406f38c66SRichard Henderson }
271506f38c66SRichard Henderson 
271606f38c66SRichard Henderson /**
271706f38c66SRichard Henderson  * pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t size, uintptr_t brk)
271806f38c66SRichard Henderson  * @addr: host address
271906f38c66SRichard Henderson  * @addr_last: host last address
272006f38c66SRichard Henderson  * @brk: host brk
272106f38c66SRichard Henderson  *
272206f38c66SRichard Henderson  * Like pgb_try_mmap, but additionally reserve some memory following brk.
272306f38c66SRichard Henderson  */
272406f38c66SRichard Henderson static int pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t addr_last,
272506f38c66SRichard Henderson                                  uintptr_t brk, bool keep)
272606f38c66SRichard Henderson {
272706f38c66SRichard Henderson     uintptr_t brk_last = brk + 16 * MiB - 1;
272806f38c66SRichard Henderson 
272906f38c66SRichard Henderson     /* Do not map anything close to the host brk. */
273006f38c66SRichard Henderson     if (addr <= brk_last && brk <= addr_last) {
273106f38c66SRichard Henderson         return 0;
273206f38c66SRichard Henderson     }
273306f38c66SRichard Henderson     return pgb_try_mmap(addr, addr_last, keep);
273406f38c66SRichard Henderson }
273506f38c66SRichard Henderson 
273606f38c66SRichard Henderson /**
273706f38c66SRichard Henderson  * pgb_try_mmap_set:
273806f38c66SRichard Henderson  * @ga: set of guest addrs
273906f38c66SRichard Henderson  * @base: guest_base
274006f38c66SRichard Henderson  * @brk: host brk
274106f38c66SRichard Henderson  *
274206f38c66SRichard Henderson  * Return true if all @ga can be mapped by the host at @base.
274306f38c66SRichard Henderson  * On success, retain the mapping at index 0 for reserved_va.
274406f38c66SRichard Henderson  */
274506f38c66SRichard Henderson 
274606f38c66SRichard Henderson typedef struct PGBAddrs {
274706f38c66SRichard Henderson     uintptr_t bounds[3][2]; /* start/last pairs */
274806f38c66SRichard Henderson     int nbounds;
274906f38c66SRichard Henderson } PGBAddrs;
275006f38c66SRichard Henderson 
275106f38c66SRichard Henderson static bool pgb_try_mmap_set(const PGBAddrs *ga, uintptr_t base, uintptr_t brk)
275206f38c66SRichard Henderson {
275306f38c66SRichard Henderson     for (int i = ga->nbounds - 1; i >= 0; --i) {
275406f38c66SRichard Henderson         if (pgb_try_mmap_skip_brk(ga->bounds[i][0] + base,
275506f38c66SRichard Henderson                                   ga->bounds[i][1] + base,
275606f38c66SRichard Henderson                                   brk, i == 0 && reserved_va) <= 0) {
275706f38c66SRichard Henderson             return false;
275806f38c66SRichard Henderson         }
275906f38c66SRichard Henderson     }
276006f38c66SRichard Henderson     return true;
276106f38c66SRichard Henderson }
276206f38c66SRichard Henderson 
276306f38c66SRichard Henderson /**
276406f38c66SRichard Henderson  * pgb_addr_set:
276506f38c66SRichard Henderson  * @ga: output set of guest addrs
276606f38c66SRichard Henderson  * @guest_loaddr: guest image low address
276706f38c66SRichard Henderson  * @guest_loaddr: guest image high address
276806f38c66SRichard Henderson  * @identity: create for identity mapping
276906f38c66SRichard Henderson  *
277006f38c66SRichard Henderson  * Fill in @ga with the image, COMMPAGE and NULL page.
277106f38c66SRichard Henderson  */
277206f38c66SRichard Henderson static bool pgb_addr_set(PGBAddrs *ga, abi_ulong guest_loaddr,
277306f38c66SRichard Henderson                          abi_ulong guest_hiaddr, bool try_identity)
277406f38c66SRichard Henderson {
277506f38c66SRichard Henderson     int n;
277606f38c66SRichard Henderson 
277706f38c66SRichard Henderson     /*
277806f38c66SRichard Henderson      * With a low commpage, or a guest mapped very low,
277906f38c66SRichard Henderson      * we may not be able to use the identity map.
278006f38c66SRichard Henderson      */
278106f38c66SRichard Henderson     if (try_identity) {
278206f38c66SRichard Henderson         if (LO_COMMPAGE != -1 && LO_COMMPAGE < mmap_min_addr) {
278306f38c66SRichard Henderson             return false;
278406f38c66SRichard Henderson         }
278506f38c66SRichard Henderson         if (guest_loaddr != 0 && guest_loaddr < mmap_min_addr) {
278606f38c66SRichard Henderson             return false;
278706f38c66SRichard Henderson         }
278806f38c66SRichard Henderson     }
278906f38c66SRichard Henderson 
279006f38c66SRichard Henderson     memset(ga, 0, sizeof(*ga));
279106f38c66SRichard Henderson     n = 0;
279206f38c66SRichard Henderson 
279306f38c66SRichard Henderson     if (reserved_va) {
279406f38c66SRichard Henderson         ga->bounds[n][0] = try_identity ? mmap_min_addr : 0;
279506f38c66SRichard Henderson         ga->bounds[n][1] = reserved_va;
279606f38c66SRichard Henderson         n++;
279706f38c66SRichard Henderson         /* LO_COMMPAGE and NULL handled by reserving from 0. */
279806f38c66SRichard Henderson     } else {
279906f38c66SRichard Henderson         /* Add any LO_COMMPAGE or NULL page. */
280006f38c66SRichard Henderson         if (LO_COMMPAGE != -1) {
280106f38c66SRichard Henderson             ga->bounds[n][0] = 0;
280206f38c66SRichard Henderson             ga->bounds[n][1] = LO_COMMPAGE + TARGET_PAGE_SIZE - 1;
280306f38c66SRichard Henderson             n++;
280406f38c66SRichard Henderson         } else if (!try_identity) {
280506f38c66SRichard Henderson             ga->bounds[n][0] = 0;
280606f38c66SRichard Henderson             ga->bounds[n][1] = TARGET_PAGE_SIZE - 1;
280706f38c66SRichard Henderson             n++;
280806f38c66SRichard Henderson         }
280906f38c66SRichard Henderson 
281006f38c66SRichard Henderson         /* Add the guest image for ET_EXEC. */
281106f38c66SRichard Henderson         if (guest_loaddr) {
281206f38c66SRichard Henderson             ga->bounds[n][0] = guest_loaddr;
281306f38c66SRichard Henderson             ga->bounds[n][1] = guest_hiaddr;
281406f38c66SRichard Henderson             n++;
281506f38c66SRichard Henderson         }
281606f38c66SRichard Henderson     }
281706f38c66SRichard Henderson 
281806f38c66SRichard Henderson     /*
281906f38c66SRichard Henderson      * Temporarily disable
282006f38c66SRichard Henderson      *   "comparison is always false due to limited range of data type"
282106f38c66SRichard Henderson      * due to comparison between unsigned and (possible) 0.
282206f38c66SRichard Henderson      */
282306f38c66SRichard Henderson #pragma GCC diagnostic push
282406f38c66SRichard Henderson #pragma GCC diagnostic ignored "-Wtype-limits"
282506f38c66SRichard Henderson 
282606f38c66SRichard Henderson     /* Add any HI_COMMPAGE not covered by reserved_va. */
282706f38c66SRichard Henderson     if (reserved_va < HI_COMMPAGE) {
282806f38c66SRichard Henderson         ga->bounds[n][0] = HI_COMMPAGE & qemu_host_page_mask;
282906f38c66SRichard Henderson         ga->bounds[n][1] = HI_COMMPAGE + TARGET_PAGE_SIZE - 1;
283006f38c66SRichard Henderson         n++;
283106f38c66SRichard Henderson     }
283206f38c66SRichard Henderson 
283306f38c66SRichard Henderson #pragma GCC diagnostic pop
283406f38c66SRichard Henderson 
283506f38c66SRichard Henderson     ga->nbounds = n;
283606f38c66SRichard Henderson     return true;
283706f38c66SRichard Henderson }
283806f38c66SRichard Henderson 
2839ee947430SAlex Bennée static void pgb_fail_in_use(const char *image_name)
2840ee947430SAlex Bennée {
2841ee947430SAlex Bennée     error_report("%s: requires virtual address space that is in use "
2842ee947430SAlex Bennée                  "(omit the -B option or choose a different value)",
2843ee947430SAlex Bennée                  image_name);
2844ee947430SAlex Bennée     exit(EXIT_FAILURE);
2845ee947430SAlex Bennée }
2846ee947430SAlex Bennée 
284706f38c66SRichard Henderson static void pgb_fixed(const char *image_name, uintptr_t guest_loaddr,
284806f38c66SRichard Henderson                       uintptr_t guest_hiaddr, uintptr_t align)
2849ee947430SAlex Bennée {
285006f38c66SRichard Henderson     PGBAddrs ga;
285106f38c66SRichard Henderson     uintptr_t brk = (uintptr_t)sbrk(0);
2852ee947430SAlex Bennée 
2853ee947430SAlex Bennée     if (!QEMU_IS_ALIGNED(guest_base, align)) {
28545ca870b9SRichard Henderson         fprintf(stderr, "Requested guest base %p does not satisfy "
285506f38c66SRichard Henderson                 "host minimum alignment (0x%" PRIxPTR ")\n",
28565ca870b9SRichard Henderson                 (void *)guest_base, align);
2857ee947430SAlex Bennée         exit(EXIT_FAILURE);
2858ee947430SAlex Bennée     }
2859ee947430SAlex Bennée 
286006f38c66SRichard Henderson     if (!pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, !guest_base)
286106f38c66SRichard Henderson         || !pgb_try_mmap_set(&ga, guest_base, brk)) {
2862ee947430SAlex Bennée         pgb_fail_in_use(image_name);
2863ee947430SAlex Bennée     }
2864ee947430SAlex Bennée }
2865ee947430SAlex Bennée 
2866ad592e37SAlex Bennée /**
2867dd558855SRichard Henderson  * pgb_find_fallback:
2868ad592e37SAlex Bennée  *
2869dd558855SRichard Henderson  * This is a fallback method for finding holes in the host address space
2870dd558855SRichard Henderson  * if we don't have the benefit of being able to access /proc/self/map.
2871dd558855SRichard Henderson  * It can potentially take a very long time as we can only dumbly iterate
2872dd558855SRichard Henderson  * up the host address space seeing if the allocation would work.
2873ad592e37SAlex Bennée  */
2874dd558855SRichard Henderson static uintptr_t pgb_find_fallback(const PGBAddrs *ga, uintptr_t align,
2875dd558855SRichard Henderson                                    uintptr_t brk)
2876ad592e37SAlex Bennée {
2877dd558855SRichard Henderson     /* TODO: come up with a better estimate of how much to skip. */
2878dd558855SRichard Henderson     uintptr_t skip = sizeof(uintptr_t) == 4 ? MiB : GiB;
2879ad592e37SAlex Bennée 
2880dd558855SRichard Henderson     for (uintptr_t base = skip; ; base += skip) {
2881dd558855SRichard Henderson         base = ROUND_UP(base, align);
2882dd558855SRichard Henderson         if (pgb_try_mmap_set(ga, base, brk)) {
2883dd558855SRichard Henderson             return base;
2884dd558855SRichard Henderson         }
2885dd558855SRichard Henderson         if (base >= -skip) {
2886dd558855SRichard Henderson             return -1;
2887dd558855SRichard Henderson         }
2888dd558855SRichard Henderson     }
2889dd558855SRichard Henderson }
2890dd558855SRichard Henderson 
2891dd558855SRichard Henderson static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base,
2892dd558855SRichard Henderson                                IntervalTreeRoot *root)
2893dd558855SRichard Henderson {
2894dd558855SRichard Henderson     for (int i = ga->nbounds - 1; i >= 0; --i) {
2895dd558855SRichard Henderson         uintptr_t s = base + ga->bounds[i][0];
2896dd558855SRichard Henderson         uintptr_t l = base + ga->bounds[i][1];
2897dd558855SRichard Henderson         IntervalTreeNode *n;
2898dd558855SRichard Henderson 
2899dd558855SRichard Henderson         if (l < s) {
2900dd558855SRichard Henderson             /* Wraparound. Skip to advance S to mmap_min_addr. */
2901dd558855SRichard Henderson             return mmap_min_addr - s;
2902dd558855SRichard Henderson         }
2903dd558855SRichard Henderson 
2904dd558855SRichard Henderson         n = interval_tree_iter_first(root, s, l);
2905dd558855SRichard Henderson         if (n != NULL) {
2906dd558855SRichard Henderson             /* Conflict.  Skip to advance S to LAST + 1. */
2907dd558855SRichard Henderson             return n->last - s + 1;
2908dd558855SRichard Henderson         }
2909dd558855SRichard Henderson     }
2910dd558855SRichard Henderson     return 0;  /* success */
2911dd558855SRichard Henderson }
2912dd558855SRichard Henderson 
2913dd558855SRichard Henderson static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root,
2914dd558855SRichard Henderson                                 uintptr_t align, uintptr_t brk)
2915dd558855SRichard Henderson {
2916dd558855SRichard Henderson     uintptr_t last = mmap_min_addr;
2917dd558855SRichard Henderson     uintptr_t base, skip;
2918ad592e37SAlex Bennée 
2919ad592e37SAlex Bennée     while (true) {
2920dd558855SRichard Henderson         base = ROUND_UP(last, align);
2921dd558855SRichard Henderson         if (base < last) {
2922ad592e37SAlex Bennée             return -1;
2923ad592e37SAlex Bennée         }
2924dd558855SRichard Henderson 
2925dd558855SRichard Henderson         skip = pgb_try_itree(ga, base, root);
2926dd558855SRichard Henderson         if (skip == 0) {
2927dd558855SRichard Henderson             break;
29282667e069SAlex Bennée         }
2929dd558855SRichard Henderson 
2930dd558855SRichard Henderson         last = base + skip;
2931dd558855SRichard Henderson         if (last < base) {
2932dd558855SRichard Henderson             return -1;
2933ad592e37SAlex Bennée         }
2934ad592e37SAlex Bennée     }
2935ad592e37SAlex Bennée 
2936dd558855SRichard Henderson     /*
2937dd558855SRichard Henderson      * We've chosen 'base' based on holes in the interval tree,
2938dd558855SRichard Henderson      * but we don't yet know if it is a valid host address.
2939dd558855SRichard Henderson      * Because it is the first matching hole, if the host addresses
2940dd558855SRichard Henderson      * are invalid we know there are no further matches.
2941dd558855SRichard Henderson      */
2942dd558855SRichard Henderson     return pgb_try_mmap_set(ga, base, brk) ? base : -1;
2943dd558855SRichard Henderson }
2944dd558855SRichard Henderson 
2945dd558855SRichard Henderson static void pgb_dynamic(const char *image_name, uintptr_t guest_loaddr,
2946dd558855SRichard Henderson                         uintptr_t guest_hiaddr, uintptr_t align)
2947ee947430SAlex Bennée {
2948dd558855SRichard Henderson     IntervalTreeRoot *root;
2949dd558855SRichard Henderson     uintptr_t brk, ret;
2950dd558855SRichard Henderson     PGBAddrs ga;
2951ee947430SAlex Bennée 
2952ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_loaddr, align));
2953ee947430SAlex Bennée 
2954dd558855SRichard Henderson     /* Try the identity map first. */
2955dd558855SRichard Henderson     if (pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, true)) {
2956dd558855SRichard Henderson         brk = (uintptr_t)sbrk(0);
2957dd558855SRichard Henderson         if (pgb_try_mmap_set(&ga, 0, brk)) {
2958dd558855SRichard Henderson             guest_base = 0;
2959dd558855SRichard Henderson             return;
2960dd558855SRichard Henderson         }
2961dd558855SRichard Henderson     }
2962dd558855SRichard Henderson 
2963dd558855SRichard Henderson     /*
2964dd558855SRichard Henderson      * Rebuild the address set for non-identity map.
2965dd558855SRichard Henderson      * This differs in the mapping of the guest NULL page.
2966dd558855SRichard Henderson      */
2967dd558855SRichard Henderson     pgb_addr_set(&ga, guest_loaddr, guest_hiaddr, false);
2968dd558855SRichard Henderson 
2969dd558855SRichard Henderson     root = read_self_maps();
2970ee947430SAlex Bennée 
2971ee947430SAlex Bennée     /* Read brk after we've read the maps, which will malloc. */
2972ee947430SAlex Bennée     brk = (uintptr_t)sbrk(0);
2973ee947430SAlex Bennée 
2974dd558855SRichard Henderson     if (!root) {
2975dd558855SRichard Henderson         ret = pgb_find_fallback(&ga, align, brk);
2976ee947430SAlex Bennée     } else {
2977ee947430SAlex Bennée         /*
2978dd558855SRichard Henderson          * Reserve the area close to the host brk.
2979dd558855SRichard Henderson          * This will be freed with the rest of the tree.
2980ee947430SAlex Bennée          */
2981dd558855SRichard Henderson         IntervalTreeNode *b = g_new0(IntervalTreeNode, 1);
2982dd558855SRichard Henderson         b->start = brk;
2983dd558855SRichard Henderson         b->last = brk + 16 * MiB - 1;
2984dd558855SRichard Henderson         interval_tree_insert(b, root);
2985dd558855SRichard Henderson 
2986dd558855SRichard Henderson         ret = pgb_find_itree(&ga, root, align, brk);
2987dd558855SRichard Henderson         free_self_maps(root);
2988ee947430SAlex Bennée     }
2989ee947430SAlex Bennée 
2990dd558855SRichard Henderson     if (ret == -1) {
2991dd558855SRichard Henderson         int w = TARGET_LONG_BITS / 4;
2992dd558855SRichard Henderson 
2993dd558855SRichard Henderson         error_report("%s: Unable to find a guest_base to satisfy all "
2994dd558855SRichard Henderson                      "guest address mapping requirements", image_name);
2995dd558855SRichard Henderson 
2996dd558855SRichard Henderson         for (int i = 0; i < ga.nbounds; ++i) {
2997dd558855SRichard Henderson             error_printf("  %0*" PRIx64 "-%0*" PRIx64 "\n",
2998dd558855SRichard Henderson                          w, (uint64_t)ga.bounds[i][0],
2999dd558855SRichard Henderson                          w, (uint64_t)ga.bounds[i][1]);
3000dd558855SRichard Henderson         }
3001ee947430SAlex Bennée         exit(EXIT_FAILURE);
3002ee947430SAlex Bennée     }
3003dd558855SRichard Henderson     guest_base = ret;
3004ee947430SAlex Bennée }
3005ee947430SAlex Bennée 
3006ee947430SAlex Bennée void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
3007ee947430SAlex Bennée                       abi_ulong guest_hiaddr)
3008dce10401SMeador Inge {
300930ab9ef2SRichard Henderson     /* In order to use host shmat, we must be able to honor SHMLBA.  */
3010ee947430SAlex Bennée     uintptr_t align = MAX(SHMLBA, qemu_host_page_size);
3011dce10401SMeador Inge 
30120c441aebSRichard Henderson     /* Sanity check the guest binary. */
30130c441aebSRichard Henderson     if (reserved_va) {
30140c441aebSRichard Henderson         if (guest_hiaddr > reserved_va) {
30150c441aebSRichard Henderson             error_report("%s: requires more than reserved virtual "
30160c441aebSRichard Henderson                          "address space (0x%" PRIx64 " > 0x%lx)",
30170c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr, reserved_va);
30180c441aebSRichard Henderson             exit(EXIT_FAILURE);
30190c441aebSRichard Henderson         }
30200c441aebSRichard Henderson     } else {
30210c441aebSRichard Henderson         if (guest_hiaddr != (uintptr_t)guest_hiaddr) {
30220c441aebSRichard Henderson             error_report("%s: requires more virtual address space "
30230c441aebSRichard Henderson                          "than the host can provide (0x%" PRIx64 ")",
30240c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr + 1);
30250c441aebSRichard Henderson             exit(EXIT_FAILURE);
30260c441aebSRichard Henderson         }
30270c441aebSRichard Henderson     }
30280c441aebSRichard Henderson 
3029ee947430SAlex Bennée     if (have_guest_base) {
303006f38c66SRichard Henderson         pgb_fixed(image_name, guest_loaddr, guest_hiaddr, align);
3031293f2060SLuke Shumaker     } else {
3032dd558855SRichard Henderson         pgb_dynamic(image_name, guest_loaddr, guest_hiaddr, align);
3033806d1021SMeador Inge     }
3034806d1021SMeador Inge 
3035ee947430SAlex Bennée     /* Reserve and initialize the commpage. */
3036ee947430SAlex Bennée     if (!init_guest_commpage()) {
303706f38c66SRichard Henderson         /* We have already probed for the commpage being free. */
303806f38c66SRichard Henderson         g_assert_not_reached();
3039dce10401SMeador Inge     }
3040dce10401SMeador Inge 
3041ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_base, align));
3042ee947430SAlex Bennée     qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space "
3043ee947430SAlex Bennée                   "@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
3044dce10401SMeador Inge }
3045dce10401SMeador Inge 
304683f990ebSRichard Henderson enum {
304783f990ebSRichard Henderson     /* The string "GNU\0" as a magic number. */
304883f990ebSRichard Henderson     GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
304983f990ebSRichard Henderson     NOTE_DATA_SZ = 1 * KiB,
305083f990ebSRichard Henderson     NOTE_NAME_SZ = 4,
305183f990ebSRichard Henderson     ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
305283f990ebSRichard Henderson };
305383f990ebSRichard Henderson 
305483f990ebSRichard Henderson /*
305583f990ebSRichard Henderson  * Process a single gnu_property entry.
305683f990ebSRichard Henderson  * Return false for error.
305783f990ebSRichard Henderson  */
305883f990ebSRichard Henderson static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
305983f990ebSRichard Henderson                                struct image_info *info, bool have_prev_type,
306083f990ebSRichard Henderson                                uint32_t *prev_type, Error **errp)
306183f990ebSRichard Henderson {
306283f990ebSRichard Henderson     uint32_t pr_type, pr_datasz, step;
306383f990ebSRichard Henderson 
306483f990ebSRichard Henderson     if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
306583f990ebSRichard Henderson         goto error_data;
306683f990ebSRichard Henderson     }
306783f990ebSRichard Henderson     datasz -= *off;
306883f990ebSRichard Henderson     data += *off / sizeof(uint32_t);
306983f990ebSRichard Henderson 
307083f990ebSRichard Henderson     if (datasz < 2 * sizeof(uint32_t)) {
307183f990ebSRichard Henderson         goto error_data;
307283f990ebSRichard Henderson     }
307383f990ebSRichard Henderson     pr_type = data[0];
307483f990ebSRichard Henderson     pr_datasz = data[1];
307583f990ebSRichard Henderson     data += 2;
307683f990ebSRichard Henderson     datasz -= 2 * sizeof(uint32_t);
307783f990ebSRichard Henderson     step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
307883f990ebSRichard Henderson     if (step > datasz) {
307983f990ebSRichard Henderson         goto error_data;
308083f990ebSRichard Henderson     }
308183f990ebSRichard Henderson 
308283f990ebSRichard Henderson     /* Properties are supposed to be unique and sorted on pr_type. */
308383f990ebSRichard Henderson     if (have_prev_type && pr_type <= *prev_type) {
308483f990ebSRichard Henderson         if (pr_type == *prev_type) {
308583f990ebSRichard Henderson             error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
308683f990ebSRichard Henderson         } else {
308783f990ebSRichard Henderson             error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
308883f990ebSRichard Henderson         }
308983f990ebSRichard Henderson         return false;
309083f990ebSRichard Henderson     }
309183f990ebSRichard Henderson     *prev_type = pr_type;
309283f990ebSRichard Henderson 
309383f990ebSRichard Henderson     if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
309483f990ebSRichard Henderson         return false;
309583f990ebSRichard Henderson     }
309683f990ebSRichard Henderson 
309783f990ebSRichard Henderson     *off += 2 * sizeof(uint32_t) + step;
309883f990ebSRichard Henderson     return true;
309983f990ebSRichard Henderson 
310083f990ebSRichard Henderson  error_data:
310183f990ebSRichard Henderson     error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
310283f990ebSRichard Henderson     return false;
310383f990ebSRichard Henderson }
310483f990ebSRichard Henderson 
310583f990ebSRichard Henderson /* Process NT_GNU_PROPERTY_TYPE_0. */
31063bd02386SRichard Henderson static bool parse_elf_properties(const ImageSource *src,
310783f990ebSRichard Henderson                                  struct image_info *info,
310883f990ebSRichard Henderson                                  const struct elf_phdr *phdr,
310983f990ebSRichard Henderson                                  Error **errp)
311083f990ebSRichard Henderson {
311183f990ebSRichard Henderson     union {
311283f990ebSRichard Henderson         struct elf_note nhdr;
311383f990ebSRichard Henderson         uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
311483f990ebSRichard Henderson     } note;
311583f990ebSRichard Henderson 
311683f990ebSRichard Henderson     int n, off, datasz;
311783f990ebSRichard Henderson     bool have_prev_type;
311883f990ebSRichard Henderson     uint32_t prev_type;
311983f990ebSRichard Henderson 
312083f990ebSRichard Henderson     /* Unless the arch requires properties, ignore them. */
312183f990ebSRichard Henderson     if (!ARCH_USE_GNU_PROPERTY) {
312283f990ebSRichard Henderson         return true;
312383f990ebSRichard Henderson     }
312483f990ebSRichard Henderson 
312583f990ebSRichard Henderson     /* If the properties are crazy large, that's too bad. */
312683f990ebSRichard Henderson     n = phdr->p_filesz;
312783f990ebSRichard Henderson     if (n > sizeof(note)) {
312883f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too large");
312983f990ebSRichard Henderson         return false;
313083f990ebSRichard Henderson     }
313183f990ebSRichard Henderson     if (n < sizeof(note.nhdr)) {
313283f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too small");
313383f990ebSRichard Henderson         return false;
313483f990ebSRichard Henderson     }
313583f990ebSRichard Henderson 
31363bd02386SRichard Henderson     if (!imgsrc_read(&note, phdr->p_offset, n, src, errp)) {
313783f990ebSRichard Henderson         return false;
313883f990ebSRichard Henderson     }
313983f990ebSRichard Henderson 
314083f990ebSRichard Henderson     /*
314183f990ebSRichard Henderson      * The contents of a valid PT_GNU_PROPERTY is a sequence
314283f990ebSRichard Henderson      * of uint32_t -- swap them all now.
314383f990ebSRichard Henderson      */
314483f990ebSRichard Henderson #ifdef BSWAP_NEEDED
314583f990ebSRichard Henderson     for (int i = 0; i < n / 4; i++) {
314683f990ebSRichard Henderson         bswap32s(note.data + i);
314783f990ebSRichard Henderson     }
314883f990ebSRichard Henderson #endif
314983f990ebSRichard Henderson 
315083f990ebSRichard Henderson     /*
315183f990ebSRichard Henderson      * Note that nhdr is 3 words, and that the "name" described by namesz
315283f990ebSRichard Henderson      * immediately follows nhdr and is thus at the 4th word.  Further, all
315383f990ebSRichard Henderson      * of the inputs to the kernel's round_up are multiples of 4.
315483f990ebSRichard Henderson      */
315583f990ebSRichard Henderson     if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
315683f990ebSRichard Henderson         note.nhdr.n_namesz != NOTE_NAME_SZ ||
315783f990ebSRichard Henderson         note.data[3] != GNU0_MAGIC) {
315883f990ebSRichard Henderson         error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
315983f990ebSRichard Henderson         return false;
316083f990ebSRichard Henderson     }
316183f990ebSRichard Henderson     off = sizeof(note.nhdr) + NOTE_NAME_SZ;
316283f990ebSRichard Henderson 
316383f990ebSRichard Henderson     datasz = note.nhdr.n_descsz + off;
316483f990ebSRichard Henderson     if (datasz > n) {
316583f990ebSRichard Henderson         error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
316683f990ebSRichard Henderson         return false;
316783f990ebSRichard Henderson     }
316883f990ebSRichard Henderson 
316983f990ebSRichard Henderson     have_prev_type = false;
317083f990ebSRichard Henderson     prev_type = 0;
317183f990ebSRichard Henderson     while (1) {
317283f990ebSRichard Henderson         if (off == datasz) {
317383f990ebSRichard Henderson             return true;  /* end, exit ok */
317483f990ebSRichard Henderson         }
317583f990ebSRichard Henderson         if (!parse_elf_property(note.data, &off, datasz, info,
317683f990ebSRichard Henderson                                 have_prev_type, &prev_type, errp)) {
317783f990ebSRichard Henderson             return false;
317883f990ebSRichard Henderson         }
317983f990ebSRichard Henderson         have_prev_type = true;
318083f990ebSRichard Henderson     }
318183f990ebSRichard Henderson }
318283f990ebSRichard Henderson 
31833bd02386SRichard Henderson /**
31843bd02386SRichard Henderson  * load_elf_image: Load an ELF image into the address space.
31853bd02386SRichard Henderson  * @image_name: the filename of the image, to use in error messages.
31863bd02386SRichard Henderson  * @src: the ImageSource from which to read.
31873bd02386SRichard Henderson  * @info: info collected from the loaded image.
31883bd02386SRichard Henderson  * @ehdr: the ELF header, not yet bswapped.
31893bd02386SRichard Henderson  * @pinterp_name: record any PT_INTERP string found.
31903bd02386SRichard Henderson  *
31913bd02386SRichard Henderson  * On return: @info values will be filled in, as necessary or available.
31923bd02386SRichard Henderson  */
319331e31b8aSbellard 
31943bd02386SRichard Henderson static void load_elf_image(const char *image_name, const ImageSource *src,
319540d487eeSRichard Henderson                            struct image_info *info, struct elfhdr *ehdr,
31963bd02386SRichard Henderson                            char **pinterp_name)
319731e31b8aSbellard {
31983bd02386SRichard Henderson     g_autofree struct elf_phdr *phdr = NULL;
31998e62a717SRichard Henderson     abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
32003bd02386SRichard Henderson     int i, prot_exec;
3201c7f17e7bSRichard Henderson     Error *err = NULL;
320231e31b8aSbellard 
32033bd02386SRichard Henderson     /*
32043bd02386SRichard Henderson      * First of all, some simple consistency checks.
32053bd02386SRichard Henderson      * Note that we rely on the bswapped ehdr staying in bprm_buf,
32063bd02386SRichard Henderson      * for later use by load_elf_binary and create_elf_tables.
32073bd02386SRichard Henderson      */
32083bd02386SRichard Henderson     if (!imgsrc_read(ehdr, 0, sizeof(*ehdr), src, &err)) {
32093bd02386SRichard Henderson         goto exit_errmsg;
32103bd02386SRichard Henderson     }
32118e62a717SRichard Henderson     if (!elf_check_ident(ehdr)) {
3212c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
32138e62a717SRichard Henderson         goto exit_errmsg;
32148e62a717SRichard Henderson     }
32158e62a717SRichard Henderson     bswap_ehdr(ehdr);
32168e62a717SRichard Henderson     if (!elf_check_ehdr(ehdr)) {
3217c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
32188e62a717SRichard Henderson         goto exit_errmsg;
321931e31b8aSbellard     }
322031e31b8aSbellard 
32213bd02386SRichard Henderson     phdr = imgsrc_read_alloc(ehdr->e_phoff,
32223bd02386SRichard Henderson                              ehdr->e_phnum * sizeof(struct elf_phdr),
32233bd02386SRichard Henderson                              src, &err);
32243bd02386SRichard Henderson     if (phdr == NULL) {
32253bd02386SRichard Henderson         goto exit_errmsg;
322631e31b8aSbellard     }
32278e62a717SRichard Henderson     bswap_phdr(phdr, ehdr->e_phnum);
322809bfb054Sbellard 
32291af02e83SMike Frysinger     info->nsegs = 0;
32301af02e83SMike Frysinger     info->pt_dynamic_addr = 0;
32311af02e83SMike Frysinger 
323298c1076cSAlex Bennée     mmap_lock();
323398c1076cSAlex Bennée 
32348a1a5274SRichard Henderson     /*
32358a1a5274SRichard Henderson      * Find the maximum size of the image and allocate an appropriate
32368a1a5274SRichard Henderson      * amount of memory to handle that.  Locate the interpreter, if any.
32378a1a5274SRichard Henderson      */
3238682674b8SRichard Henderson     loaddr = -1, hiaddr = 0;
323933143c44SLaurent Vivier     info->alignment = 0;
3240872f3d04SRichard Henderson     info->exec_stack = EXSTACK_DEFAULT;
32418e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; ++i) {
32424d9d535aSRichard Henderson         struct elf_phdr *eppnt = phdr + i;
32434d9d535aSRichard Henderson         if (eppnt->p_type == PT_LOAD) {
32444d9d535aSRichard Henderson             abi_ulong a = eppnt->p_vaddr - eppnt->p_offset;
3245682674b8SRichard Henderson             if (a < loaddr) {
3246682674b8SRichard Henderson                 loaddr = a;
3247682674b8SRichard Henderson             }
3248a3a67f54SRichard Henderson             a = eppnt->p_vaddr + eppnt->p_memsz - 1;
3249682674b8SRichard Henderson             if (a > hiaddr) {
3250682674b8SRichard Henderson                 hiaddr = a;
3251682674b8SRichard Henderson             }
32521af02e83SMike Frysinger             ++info->nsegs;
32534d9d535aSRichard Henderson             info->alignment |= eppnt->p_align;
32548a1a5274SRichard Henderson         } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
32558a1a5274SRichard Henderson             g_autofree char *interp_name = NULL;
32568a1a5274SRichard Henderson 
32578a1a5274SRichard Henderson             if (*pinterp_name) {
3258c7f17e7bSRichard Henderson                 error_setg(&err, "Multiple PT_INTERP entries");
32598a1a5274SRichard Henderson                 goto exit_errmsg;
32608a1a5274SRichard Henderson             }
3261c7f17e7bSRichard Henderson 
32623bd02386SRichard Henderson             interp_name = imgsrc_read_alloc(eppnt->p_offset, eppnt->p_filesz,
32633bd02386SRichard Henderson                                             src, &err);
32643bd02386SRichard Henderson             if (interp_name == NULL) {
32653bd02386SRichard Henderson                 goto exit_errmsg;
32668a1a5274SRichard Henderson             }
32678a1a5274SRichard Henderson             if (interp_name[eppnt->p_filesz - 1] != 0) {
3268c7f17e7bSRichard Henderson                 error_setg(&err, "Invalid PT_INTERP entry");
32698a1a5274SRichard Henderson                 goto exit_errmsg;
32708a1a5274SRichard Henderson             }
32718a1a5274SRichard Henderson             *pinterp_name = g_steal_pointer(&interp_name);
327283f990ebSRichard Henderson         } else if (eppnt->p_type == PT_GNU_PROPERTY) {
32733bd02386SRichard Henderson             if (!parse_elf_properties(src, info, eppnt, &err)) {
327483f990ebSRichard Henderson                 goto exit_errmsg;
327583f990ebSRichard Henderson             }
3276872f3d04SRichard Henderson         } else if (eppnt->p_type == PT_GNU_STACK) {
3277872f3d04SRichard Henderson             info->exec_stack = eppnt->p_flags & PF_X;
3278682674b8SRichard Henderson         }
3279682674b8SRichard Henderson     }
3280682674b8SRichard Henderson 
32811ea06dedSRichard Henderson     load_addr = loaddr;
32821ea06dedSRichard Henderson 
32836fd59449SRichard Henderson     if (pinterp_name != NULL) {
32846fd59449SRichard Henderson         if (ehdr->e_type == ET_EXEC) {
32856fd59449SRichard Henderson             /*
32866fd59449SRichard Henderson              * Make sure that the low address does not conflict with
32876fd59449SRichard Henderson              * MMAP_MIN_ADDR or the QEMU application itself.
32886fd59449SRichard Henderson              */
32896fd59449SRichard Henderson             probe_guest_base(image_name, loaddr, hiaddr);
3290ee947430SAlex Bennée         } else {
32911ea06dedSRichard Henderson             abi_ulong align;
32921ea06dedSRichard Henderson 
3293ee947430SAlex Bennée             /*
3294ee947430SAlex Bennée              * The binary is dynamic, but we still need to
3295ee947430SAlex Bennée              * select guest_base.  In this case we pass a size.
3296ee947430SAlex Bennée              */
3297ee947430SAlex Bennée             probe_guest_base(image_name, 0, hiaddr - loaddr);
32981ea06dedSRichard Henderson 
32991ea06dedSRichard Henderson             /*
33001ea06dedSRichard Henderson              * Avoid collision with the loader by providing a different
33011ea06dedSRichard Henderson              * default load address.
33021ea06dedSRichard Henderson              */
33031ea06dedSRichard Henderson             load_addr += elf_et_dyn_base;
33041ea06dedSRichard Henderson 
33051ea06dedSRichard Henderson             /*
33061ea06dedSRichard Henderson              * TODO: Better support for mmap alignment is desirable.
33071ea06dedSRichard Henderson              * Since we do not have complete control over the guest
33081ea06dedSRichard Henderson              * address space, we prefer the kernel to choose some address
33091ea06dedSRichard Henderson              * rather than force the use of LOAD_ADDR via MAP_FIXED.
33101ea06dedSRichard Henderson              * But without MAP_FIXED we cannot guarantee alignment,
33111ea06dedSRichard Henderson              * only suggest it.
33121ea06dedSRichard Henderson              */
33131ea06dedSRichard Henderson             align = pow2ceil(info->alignment);
33141ea06dedSRichard Henderson             if (align) {
33151ea06dedSRichard Henderson                 load_addr &= -align;
33161ea06dedSRichard Henderson             }
33176fd59449SRichard Henderson         }
33186fd59449SRichard Henderson     }
33196fd59449SRichard Henderson 
33206fd59449SRichard Henderson     /*
33216fd59449SRichard Henderson      * Reserve address space for all of this.
33226fd59449SRichard Henderson      *
3323ad25051bSRichard Henderson      * In the case of ET_EXEC, we supply MAP_FIXED_NOREPLACE so that we get
3324ad25051bSRichard Henderson      * exactly the address range that is required.  Without reserved_va,
3325ad25051bSRichard Henderson      * the guest address space is not isolated.  We have attempted to avoid
3326ad25051bSRichard Henderson      * conflict with the host program itself via probe_guest_base, but using
3327ad25051bSRichard Henderson      * MAP_FIXED_NOREPLACE instead of MAP_FIXED provides an extra check.
33286fd59449SRichard Henderson      *
33296fd59449SRichard Henderson      * Otherwise this is ET_DYN, and we are searching for a location
33306fd59449SRichard Henderson      * that can hold the memory space required.  If the image is
33311ea06dedSRichard Henderson      * pre-linked, LOAD_ADDR will be non-zero, and the kernel should
33326fd59449SRichard Henderson      * honor that address if it happens to be free.
33336fd59449SRichard Henderson      *
33346fd59449SRichard Henderson      * In both cases, we will overwrite pages in this range with mappings
33356fd59449SRichard Henderson      * from the executable.
33366fd59449SRichard Henderson      */
33371ea06dedSRichard Henderson     load_addr = target_mmap(load_addr, (size_t)hiaddr - loaddr + 1, PROT_NONE,
33386fd59449SRichard Henderson                             MAP_PRIVATE | MAP_ANON | MAP_NORESERVE |
3339ad25051bSRichard Henderson                             (ehdr->e_type == ET_EXEC ? MAP_FIXED_NOREPLACE : 0),
334009bfb054Sbellard                             -1, 0);
3341682674b8SRichard Henderson     if (load_addr == -1) {
3342c7f17e7bSRichard Henderson         goto exit_mmap;
334309bfb054Sbellard     }
3344682674b8SRichard Henderson     load_bias = load_addr - loaddr;
334509bfb054Sbellard 
3346a99856cdSChristophe Lyon     if (elf_is_fdpic(ehdr)) {
33471af02e83SMike Frysinger         struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
33487267c094SAnthony Liguori             g_malloc(sizeof(*loadsegs) * info->nsegs);
33491af02e83SMike Frysinger 
33501af02e83SMike Frysinger         for (i = 0; i < ehdr->e_phnum; ++i) {
33511af02e83SMike Frysinger             switch (phdr[i].p_type) {
33521af02e83SMike Frysinger             case PT_DYNAMIC:
33531af02e83SMike Frysinger                 info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
33541af02e83SMike Frysinger                 break;
33551af02e83SMike Frysinger             case PT_LOAD:
33561af02e83SMike Frysinger                 loadsegs->addr = phdr[i].p_vaddr + load_bias;
33571af02e83SMike Frysinger                 loadsegs->p_vaddr = phdr[i].p_vaddr;
33581af02e83SMike Frysinger                 loadsegs->p_memsz = phdr[i].p_memsz;
33591af02e83SMike Frysinger                 ++loadsegs;
33601af02e83SMike Frysinger                 break;
33611af02e83SMike Frysinger             }
33621af02e83SMike Frysinger         }
33631af02e83SMike Frysinger     }
33641af02e83SMike Frysinger 
33658e62a717SRichard Henderson     info->load_bias = load_bias;
3366dc12567aSJosh Kunz     info->code_offset = load_bias;
3367dc12567aSJosh Kunz     info->data_offset = load_bias;
33688e62a717SRichard Henderson     info->load_addr = load_addr;
33698e62a717SRichard Henderson     info->entry = ehdr->e_entry + load_bias;
33708e62a717SRichard Henderson     info->start_code = -1;
33718e62a717SRichard Henderson     info->end_code = 0;
33728e62a717SRichard Henderson     info->start_data = -1;
33738e62a717SRichard Henderson     info->end_data = 0;
33741f356e8cSHelge Deller     /* Usual start for brk is after all sections of the main executable. */
3375aec338d6SRichard Henderson     info->brk = TARGET_PAGE_ALIGN(hiaddr + load_bias);
3376d8fd2954SPaul Brook     info->elf_flags = ehdr->e_flags;
33778e62a717SRichard Henderson 
3378e8384b37SRichard Henderson     prot_exec = PROT_EXEC;
3379e8384b37SRichard Henderson #ifdef TARGET_AARCH64
3380e8384b37SRichard Henderson     /*
3381e8384b37SRichard Henderson      * If the BTI feature is present, this indicates that the executable
3382e8384b37SRichard Henderson      * pages of the startup binary should be mapped with PROT_BTI, so that
3383e8384b37SRichard Henderson      * branch targets are enforced.
3384e8384b37SRichard Henderson      *
3385e8384b37SRichard Henderson      * The startup binary is either the interpreter or the static executable.
3386e8384b37SRichard Henderson      * The interpreter is responsible for all pages of a dynamic executable.
3387e8384b37SRichard Henderson      *
3388e8384b37SRichard Henderson      * Elf notes are backward compatible to older cpus.
3389e8384b37SRichard Henderson      * Do not enable BTI unless it is supported.
3390e8384b37SRichard Henderson      */
3391e8384b37SRichard Henderson     if ((info->note_flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
3392e8384b37SRichard Henderson         && (pinterp_name == NULL || *pinterp_name == 0)
3393e8384b37SRichard Henderson         && cpu_isar_feature(aa64_bti, ARM_CPU(thread_cpu))) {
3394e8384b37SRichard Henderson         prot_exec |= TARGET_PROT_BTI;
3395e8384b37SRichard Henderson     }
3396e8384b37SRichard Henderson #endif
3397e8384b37SRichard Henderson 
33988e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; i++) {
33998e62a717SRichard Henderson         struct elf_phdr *eppnt = phdr + i;
340031e31b8aSbellard         if (eppnt->p_type == PT_LOAD) {
34015f4e5b34SRichard Henderson             abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
340231e31b8aSbellard             int elf_prot = 0;
340331e31b8aSbellard 
3404e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_R) {
3405e5eaf570SRichard Henderson                 elf_prot |= PROT_READ;
3406e5eaf570SRichard Henderson             }
3407e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_W) {
3408e5eaf570SRichard Henderson                 elf_prot |= PROT_WRITE;
3409e5eaf570SRichard Henderson             }
3410e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_X) {
3411e8384b37SRichard Henderson                 elf_prot |= prot_exec;
3412e5eaf570SRichard Henderson             }
341331e31b8aSbellard 
3414682674b8SRichard Henderson             vaddr = load_bias + eppnt->p_vaddr;
3415e3d97d5cSRichard Henderson             vaddr_po = vaddr & ~TARGET_PAGE_MASK;
3416e3d97d5cSRichard Henderson             vaddr_ps = vaddr & TARGET_PAGE_MASK;
341722d113b5SGiuseppe Musacchio 
341822d113b5SGiuseppe Musacchio             vaddr_ef = vaddr + eppnt->p_filesz;
341922d113b5SGiuseppe Musacchio             vaddr_em = vaddr + eppnt->p_memsz;
3420682674b8SRichard Henderson 
3421d87146bcSGiuseppe Musacchio             /*
342222d113b5SGiuseppe Musacchio              * Some segments may be completely empty, with a non-zero p_memsz
342322d113b5SGiuseppe Musacchio              * but no backing file segment.
3424d87146bcSGiuseppe Musacchio              */
3425d87146bcSGiuseppe Musacchio             if (eppnt->p_filesz != 0) {
34263bd02386SRichard Henderson                 error = imgsrc_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
34275f4e5b34SRichard Henderson                                     elf_prot, MAP_PRIVATE | MAP_FIXED,
34283bd02386SRichard Henderson                                     src, eppnt->p_offset - vaddr_po);
3429e89f07d3Spbrook                 if (error == -1) {
3430c7f17e7bSRichard Henderson                     goto exit_mmap;
343131e31b8aSbellard                 }
34325f4e5b34SRichard Henderson             }
343331e31b8aSbellard 
34345f4e5b34SRichard Henderson             /* If the load segment requests extra zeros (e.g. bss), map it. */
34355f4e5b34SRichard Henderson             if (vaddr_ef < vaddr_em &&
3436e6e66b03SRichard Henderson                 !zero_bss(vaddr_ef, vaddr_em, elf_prot, &err)) {
3437e6e66b03SRichard Henderson                 goto exit_errmsg;
3438682674b8SRichard Henderson             }
34398e62a717SRichard Henderson 
34408e62a717SRichard Henderson             /* Find the full program boundaries.  */
34418e62a717SRichard Henderson             if (elf_prot & PROT_EXEC) {
34428e62a717SRichard Henderson                 if (vaddr < info->start_code) {
34438e62a717SRichard Henderson                     info->start_code = vaddr;
3444cf129f3aSRichard Henderson                 }
34458e62a717SRichard Henderson                 if (vaddr_ef > info->end_code) {
34468e62a717SRichard Henderson                     info->end_code = vaddr_ef;
34478e62a717SRichard Henderson                 }
34488e62a717SRichard Henderson             }
34498e62a717SRichard Henderson             if (elf_prot & PROT_WRITE) {
34508e62a717SRichard Henderson                 if (vaddr < info->start_data) {
34518e62a717SRichard Henderson                     info->start_data = vaddr;
34528e62a717SRichard Henderson                 }
34538e62a717SRichard Henderson                 if (vaddr_ef > info->end_data) {
34548e62a717SRichard Henderson                     info->end_data = vaddr_ef;
34558e62a717SRichard Henderson                 }
34568a045188STimothy E Baldwin             }
34575dd0db52SStefan Markovic #ifdef TARGET_MIPS
34585dd0db52SStefan Markovic         } else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
34595dd0db52SStefan Markovic             Mips_elf_abiflags_v0 abiflags;
34603bd02386SRichard Henderson 
34613bd02386SRichard Henderson             if (!imgsrc_read(&abiflags, eppnt->p_offset, sizeof(abiflags),
34623bd02386SRichard Henderson                              src, &err)) {
34635dd0db52SStefan Markovic                 goto exit_errmsg;
34645dd0db52SStefan Markovic             }
34655dd0db52SStefan Markovic             bswap_mips_abiflags(&abiflags);
3466c94cb6c9SStefan Markovic             info->fp_abi = abiflags.fp_abi;
34675dd0db52SStefan Markovic #endif
34688e62a717SRichard Henderson         }
34698e62a717SRichard Henderson     }
34708e62a717SRichard Henderson 
34718e62a717SRichard Henderson     if (info->end_data == 0) {
34728e62a717SRichard Henderson         info->start_data = info->end_code;
34738e62a717SRichard Henderson         info->end_data = info->end_code;
347431e31b8aSbellard     }
347531e31b8aSbellard 
3476682674b8SRichard Henderson     if (qemu_log_enabled()) {
3477*86cf82dcSRichard Henderson         load_symbols(ehdr, src, load_bias);
3478682674b8SRichard Henderson     }
347931e31b8aSbellard 
34803bd02386SRichard Henderson     debuginfo_report_elf(image_name, src->fd, load_bias);
34817c10cb38SIlya Leoshkevich 
348298c1076cSAlex Bennée     mmap_unlock();
348398c1076cSAlex Bennée 
34843bd02386SRichard Henderson     close(src->fd);
34858e62a717SRichard Henderson     return;
348631e31b8aSbellard 
3487c7f17e7bSRichard Henderson  exit_mmap:
3488c7f17e7bSRichard Henderson     error_setg_errno(&err, errno, "Error mapping file");
3489c7f17e7bSRichard Henderson     goto exit_errmsg;
34908e62a717SRichard Henderson  exit_errmsg:
3491c7f17e7bSRichard Henderson     error_reportf_err(err, "%s: ", image_name);
34928e62a717SRichard Henderson     exit(-1);
34938e62a717SRichard Henderson }
34948e62a717SRichard Henderson 
34958e62a717SRichard Henderson static void load_elf_interp(const char *filename, struct image_info *info,
34968e62a717SRichard Henderson                             char bprm_buf[BPRM_BUF_SIZE])
34978e62a717SRichard Henderson {
349840d487eeSRichard Henderson     struct elfhdr ehdr;
34993bd02386SRichard Henderson     ImageSource src;
35008e62a717SRichard Henderson     int fd, retval;
3501808f6563SRichard Henderson     Error *err = NULL;
35028e62a717SRichard Henderson 
35038e62a717SRichard Henderson     fd = open(path(filename), O_RDONLY);
35048e62a717SRichard Henderson     if (fd < 0) {
3505808f6563SRichard Henderson         error_setg_file_open(&err, errno, filename);
3506808f6563SRichard Henderson         error_report_err(err);
3507808f6563SRichard Henderson         exit(-1);
35088e62a717SRichard Henderson     }
35098e62a717SRichard Henderson 
35108e62a717SRichard Henderson     retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
35118e62a717SRichard Henderson     if (retval < 0) {
3512808f6563SRichard Henderson         error_setg_errno(&err, errno, "Error reading file header");
3513808f6563SRichard Henderson         error_reportf_err(err, "%s: ", filename);
3514808f6563SRichard Henderson         exit(-1);
35158e62a717SRichard Henderson     }
3516808f6563SRichard Henderson 
35173bd02386SRichard Henderson     src.fd = fd;
35183bd02386SRichard Henderson     src.cache = bprm_buf;
35193bd02386SRichard Henderson     src.cache_size = retval;
35208e62a717SRichard Henderson 
35213bd02386SRichard Henderson     load_elf_image(filename, &src, info, &ehdr, NULL);
352231e31b8aSbellard }
352331e31b8aSbellard 
352449918a75Spbrook static int symfind(const void *s0, const void *s1)
352549918a75Spbrook {
352649918a75Spbrook     struct elf_sym *sym = (struct elf_sym *)s1;
3527b6235a75SRichard Henderson     __typeof(sym->st_value) addr = *(uint64_t *)s0;
352849918a75Spbrook     int result = 0;
3529b6235a75SRichard Henderson 
3530c7c530cdSStefan Weil     if (addr < sym->st_value) {
353149918a75Spbrook         result = -1;
3532c7c530cdSStefan Weil     } else if (addr >= sym->st_value + sym->st_size) {
353349918a75Spbrook         result = 1;
353449918a75Spbrook     }
353549918a75Spbrook     return result;
353649918a75Spbrook }
353749918a75Spbrook 
3538b6235a75SRichard Henderson static const char *lookup_symbolxx(struct syminfo *s, uint64_t orig_addr)
353949918a75Spbrook {
354049918a75Spbrook #if ELF_CLASS == ELFCLASS32
354149918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf32;
354249918a75Spbrook #else
354349918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf64;
354449918a75Spbrook #endif
354549918a75Spbrook 
354649918a75Spbrook     // binary search
354749918a75Spbrook     struct elf_sym *sym;
354849918a75Spbrook 
3549c7c530cdSStefan Weil     sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
35507cba04f6SBlue Swirl     if (sym != NULL) {
355149918a75Spbrook         return s->disas_strtab + sym->st_name;
355249918a75Spbrook     }
355349918a75Spbrook 
355449918a75Spbrook     return "";
355549918a75Spbrook }
355649918a75Spbrook 
355749918a75Spbrook /* FIXME: This should use elf_ops.h  */
355849918a75Spbrook static int symcmp(const void *s0, const void *s1)
355949918a75Spbrook {
356049918a75Spbrook     struct elf_sym *sym0 = (struct elf_sym *)s0;
356149918a75Spbrook     struct elf_sym *sym1 = (struct elf_sym *)s1;
356249918a75Spbrook     return (sym0->st_value < sym1->st_value)
356349918a75Spbrook         ? -1
356449918a75Spbrook         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
356549918a75Spbrook }
356649918a75Spbrook 
3567689f936fSbellard /* Best attempt to load symbols from this ELF object. */
3568*86cf82dcSRichard Henderson static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
3569*86cf82dcSRichard Henderson                          abi_ulong load_bias)
3570689f936fSbellard {
3571682674b8SRichard Henderson     int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
3572*86cf82dcSRichard Henderson     g_autofree struct elf_shdr *shdr = NULL;
3573b9475279SCédric VINCENT     char *strings = NULL;
3574*86cf82dcSRichard Henderson     struct elf_sym *syms = NULL;
3575*86cf82dcSRichard Henderson     struct elf_sym *new_syms;
3576*86cf82dcSRichard Henderson     uint64_t segsz;
357731e31b8aSbellard 
3578682674b8SRichard Henderson     shnum = hdr->e_shnum;
3579*86cf82dcSRichard Henderson     shdr = imgsrc_read_alloc(hdr->e_shoff, shnum * sizeof(struct elf_shdr),
3580*86cf82dcSRichard Henderson                              src, NULL);
3581*86cf82dcSRichard Henderson     if (shdr == NULL) {
3582689f936fSbellard         return;
3583682674b8SRichard Henderson     }
3584682674b8SRichard Henderson 
3585682674b8SRichard Henderson     bswap_shdr(shdr, shnum);
3586682674b8SRichard Henderson     for (i = 0; i < shnum; ++i) {
3587682674b8SRichard Henderson         if (shdr[i].sh_type == SHT_SYMTAB) {
3588682674b8SRichard Henderson             sym_idx = i;
3589682674b8SRichard Henderson             str_idx = shdr[i].sh_link;
3590689f936fSbellard             goto found;
3591689f936fSbellard         }
3592689f936fSbellard     }
3593682674b8SRichard Henderson 
3594682674b8SRichard Henderson     /* There will be no symbol table if the file was stripped.  */
3595682674b8SRichard Henderson     return;
3596689f936fSbellard 
3597689f936fSbellard  found:
3598689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them.  */
3599682674b8SRichard Henderson 
36001e06262dSPeter Maydell     segsz = shdr[str_idx].sh_size;
3601*86cf82dcSRichard Henderson     strings = g_try_malloc(segsz);
3602*86cf82dcSRichard Henderson     if (!strings) {
3603*86cf82dcSRichard Henderson         goto give_up;
3604*86cf82dcSRichard Henderson     }
3605*86cf82dcSRichard Henderson     if (!imgsrc_read(strings, shdr[str_idx].sh_offset, segsz, src, NULL)) {
3606b9475279SCédric VINCENT         goto give_up;
3607682674b8SRichard Henderson     }
3608689f936fSbellard 
36091e06262dSPeter Maydell     segsz = shdr[sym_idx].sh_size;
36101e06262dSPeter Maydell     if (segsz / sizeof(struct elf_sym) > INT_MAX) {
3611*86cf82dcSRichard Henderson         /*
3612*86cf82dcSRichard Henderson          * Implausibly large symbol table: give up rather than ploughing
3613*86cf82dcSRichard Henderson          * on with the number of symbols calculation overflowing.
36141e06262dSPeter Maydell          */
36151e06262dSPeter Maydell         goto give_up;
36161e06262dSPeter Maydell     }
36171e06262dSPeter Maydell     nsyms = segsz / sizeof(struct elf_sym);
3618*86cf82dcSRichard Henderson     syms = g_try_malloc(segsz);
3619*86cf82dcSRichard Henderson     if (!syms) {
3620*86cf82dcSRichard Henderson         goto give_up;
3621*86cf82dcSRichard Henderson     }
3622*86cf82dcSRichard Henderson     if (!imgsrc_read(syms, shdr[sym_idx].sh_offset, segsz, src, NULL)) {
3623*86cf82dcSRichard Henderson         goto give_up;
3624*86cf82dcSRichard Henderson     }
3625*86cf82dcSRichard Henderson 
3626682674b8SRichard Henderson     for (i = 0; i < nsyms; ) {
362749918a75Spbrook         bswap_sym(syms + i);
3628682674b8SRichard Henderson         /* Throw away entries which we do not need.  */
3629682674b8SRichard Henderson         if (syms[i].st_shndx == SHN_UNDEF
3630682674b8SRichard Henderson             || syms[i].st_shndx >= SHN_LORESERVE
3631682674b8SRichard Henderson             || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
3632682674b8SRichard Henderson             if (i < --nsyms) {
363349918a75Spbrook                 syms[i] = syms[nsyms];
363449918a75Spbrook             }
3635682674b8SRichard Henderson         } else {
363649918a75Spbrook #if defined(TARGET_ARM) || defined (TARGET_MIPS)
363749918a75Spbrook             /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
363849918a75Spbrook             syms[i].st_value &= ~(target_ulong)1;
363949918a75Spbrook #endif
3640682674b8SRichard Henderson             syms[i].st_value += load_bias;
364149918a75Spbrook             i++;
364249918a75Spbrook         }
3643682674b8SRichard Henderson     }
364449918a75Spbrook 
3645b9475279SCédric VINCENT     /* No "useful" symbol.  */
3646b9475279SCédric VINCENT     if (nsyms == 0) {
3647b9475279SCédric VINCENT         goto give_up;
3648b9475279SCédric VINCENT     }
3649b9475279SCédric VINCENT 
3650*86cf82dcSRichard Henderson     /*
3651*86cf82dcSRichard Henderson      * Attempt to free the storage associated with the local symbols
3652*86cf82dcSRichard Henderson      * that we threw away.  Whether or not this has any effect on the
3653*86cf82dcSRichard Henderson      * memory allocation depends on the malloc implementation and how
3654*86cf82dcSRichard Henderson      * many symbols we managed to discard.
3655*86cf82dcSRichard Henderson      */
36560ef9ea29SPeter Maydell     new_syms = g_try_renew(struct elf_sym, syms, nsyms);
36578d79de6eSStefan Weil     if (new_syms == NULL) {
3658b9475279SCédric VINCENT         goto give_up;
36595d5c9930SRichard Henderson     }
36608d79de6eSStefan Weil     syms = new_syms;
36615d5c9930SRichard Henderson 
366249918a75Spbrook     qsort(syms, nsyms, sizeof(*syms), symcmp);
366349918a75Spbrook 
3664*86cf82dcSRichard Henderson     {
3665*86cf82dcSRichard Henderson         struct syminfo *s = g_new(struct syminfo, 1);
3666*86cf82dcSRichard Henderson 
3667*86cf82dcSRichard Henderson         s->disas_strtab = strings;
366849918a75Spbrook         s->disas_num_syms = nsyms;
366949918a75Spbrook #if ELF_CLASS == ELFCLASS32
367049918a75Spbrook         s->disas_symtab.elf32 = syms;
367149918a75Spbrook #else
367249918a75Spbrook         s->disas_symtab.elf64 = syms;
367349918a75Spbrook #endif
3674682674b8SRichard Henderson         s->lookup_symbol = lookup_symbolxx;
3675e80cfcfcSbellard         s->next = syminfos;
3676e80cfcfcSbellard         syminfos = s;
3677*86cf82dcSRichard Henderson     }
3678b9475279SCédric VINCENT     return;
3679b9475279SCédric VINCENT 
3680b9475279SCédric VINCENT  give_up:
36810ef9ea29SPeter Maydell     g_free(strings);
36820ef9ea29SPeter Maydell     g_free(syms);
3683689f936fSbellard }
368431e31b8aSbellard 
3685768fe76eSYunQiang Su uint32_t get_elf_eflags(int fd)
3686768fe76eSYunQiang Su {
3687768fe76eSYunQiang Su     struct elfhdr ehdr;
3688768fe76eSYunQiang Su     off_t offset;
3689768fe76eSYunQiang Su     int ret;
3690768fe76eSYunQiang Su 
3691768fe76eSYunQiang Su     /* Read ELF header */
3692768fe76eSYunQiang Su     offset = lseek(fd, 0, SEEK_SET);
3693768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3694768fe76eSYunQiang Su         return 0;
3695768fe76eSYunQiang Su     }
3696768fe76eSYunQiang Su     ret = read(fd, &ehdr, sizeof(ehdr));
3697768fe76eSYunQiang Su     if (ret < sizeof(ehdr)) {
3698768fe76eSYunQiang Su         return 0;
3699768fe76eSYunQiang Su     }
3700768fe76eSYunQiang Su     offset = lseek(fd, offset, SEEK_SET);
3701768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3702768fe76eSYunQiang Su         return 0;
3703768fe76eSYunQiang Su     }
3704768fe76eSYunQiang Su 
3705768fe76eSYunQiang Su     /* Check ELF signature */
3706768fe76eSYunQiang Su     if (!elf_check_ident(&ehdr)) {
3707768fe76eSYunQiang Su         return 0;
3708768fe76eSYunQiang Su     }
3709768fe76eSYunQiang Su 
3710768fe76eSYunQiang Su     /* check header */
3711768fe76eSYunQiang Su     bswap_ehdr(&ehdr);
3712768fe76eSYunQiang Su     if (!elf_check_ehdr(&ehdr)) {
3713768fe76eSYunQiang Su         return 0;
3714768fe76eSYunQiang Su     }
3715768fe76eSYunQiang Su 
3716768fe76eSYunQiang Su     /* return architecture id */
3717768fe76eSYunQiang Su     return ehdr.e_flags;
3718768fe76eSYunQiang Su }
3719768fe76eSYunQiang Su 
3720f0116c54SWill Newton int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
372131e31b8aSbellard {
372240d487eeSRichard Henderson     /*
372340d487eeSRichard Henderson      * We need a copy of the elf header for passing to create_elf_tables.
372440d487eeSRichard Henderson      * We will have overwritten the original when we re-use bprm->buf
372540d487eeSRichard Henderson      * while loading the interpreter.  Allocate the storage for this now
372640d487eeSRichard Henderson      * and let elf_load_image do any swapping that may be required.
372740d487eeSRichard Henderson      */
372840d487eeSRichard Henderson     struct elfhdr ehdr;
37298e62a717SRichard Henderson     struct image_info interp_info;
37308e62a717SRichard Henderson     char *elf_interpreter = NULL;
373159baae9aSStefan Brüns     char *scratch;
373231e31b8aSbellard 
3733abcac736SDaniel Santos     memset(&interp_info, 0, sizeof(interp_info));
3734abcac736SDaniel Santos #ifdef TARGET_MIPS
3735abcac736SDaniel Santos     interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
3736abcac736SDaniel Santos #endif
3737abcac736SDaniel Santos 
37383bd02386SRichard Henderson     load_elf_image(bprm->filename, &bprm->src, info, &ehdr, &elf_interpreter);
373931e31b8aSbellard 
374059baae9aSStefan Brüns     /* Do this so that we can load the interpreter, if need be.  We will
374159baae9aSStefan Brüns        change some of these later */
374259baae9aSStefan Brüns     bprm->p = setup_arg_pages(bprm, info);
374359baae9aSStefan Brüns 
374459baae9aSStefan Brüns     scratch = g_new0(char, TARGET_PAGE_SIZE);
37457c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
374659baae9aSStefan Brüns         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
374759baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
37487c4ee5bcSRichard Henderson         info->file_string = bprm->p;
374959baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
375059baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
37517c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
375259baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
375359baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
37547c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
37557c4ee5bcSRichard Henderson     } else {
37567c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
37577c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
37587c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
37597c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
37607c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
37617c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
37627c4ee5bcSRichard Henderson         info->file_string = bprm->p;
37637c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
37647c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
37657c4ee5bcSRichard Henderson     }
37667c4ee5bcSRichard Henderson 
376759baae9aSStefan Brüns     g_free(scratch);
376859baae9aSStefan Brüns 
3769e5fe0c52Spbrook     if (!bprm->p) {
3770bf858897SRichard Henderson         fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
377131e31b8aSbellard         exit(-1);
37729955ffacSRichard Henderson     }
3773379f6698SPaul Brook 
37748e62a717SRichard Henderson     if (elf_interpreter) {
37758e62a717SRichard Henderson         load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
377631e31b8aSbellard 
37771f356e8cSHelge Deller         /*
37781f356e8cSHelge Deller          * While unusual because of ELF_ET_DYN_BASE, if we are unlucky
37791f356e8cSHelge Deller          * with the mappings the interpreter can be loaded above but
37801f356e8cSHelge Deller          * near the main executable, which can leave very little room
37811f356e8cSHelge Deller          * for the heap.
37821f356e8cSHelge Deller          * If the current brk has less than 16MB, use the end of the
37831f356e8cSHelge Deller          * interpreter.
37841f356e8cSHelge Deller          */
37851f356e8cSHelge Deller         if (interp_info.brk > info->brk &&
37861f356e8cSHelge Deller             interp_info.load_bias - info->brk < 16 * MiB)  {
37871f356e8cSHelge Deller             info->brk = interp_info.brk;
37881f356e8cSHelge Deller         }
37891f356e8cSHelge Deller 
37908e62a717SRichard Henderson         /* If the program interpreter is one of these two, then assume
37918e62a717SRichard Henderson            an iBCS2 image.  Otherwise assume a native linux image.  */
379231e31b8aSbellard 
37938e62a717SRichard Henderson         if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
37948e62a717SRichard Henderson             || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
37958e62a717SRichard Henderson             info->personality = PER_SVR4;
37968e62a717SRichard Henderson 
379731e31b8aSbellard             /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
37988e62a717SRichard Henderson                and some applications "depend" upon this behavior.  Since
37998e62a717SRichard Henderson                we do not have the power to recompile these, we emulate
38008e62a717SRichard Henderson                the SVr4 behavior.  Sigh.  */
38018e62a717SRichard Henderson             target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
380268754b44SPeter Maydell                         MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
380331e31b8aSbellard         }
3804c94cb6c9SStefan Markovic #ifdef TARGET_MIPS
3805c94cb6c9SStefan Markovic         info->interp_fp_abi = interp_info.fp_abi;
3806c94cb6c9SStefan Markovic #endif
38078e62a717SRichard Henderson     }
380831e31b8aSbellard 
3809db2af69dSRichard Henderson     /*
3810db2af69dSRichard Henderson      * TODO: load a vdso, which would also contain the signal trampolines.
3811db2af69dSRichard Henderson      * Otherwise, allocate a private page to hold them.
3812db2af69dSRichard Henderson      */
3813db2af69dSRichard Henderson     if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
3814802ae45eSLaurent Vivier         abi_long tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
3815db2af69dSRichard Henderson                                           PROT_READ | PROT_WRITE,
3816db2af69dSRichard Henderson                                           MAP_PRIVATE | MAP_ANON, -1, 0);
3817802ae45eSLaurent Vivier         if (tramp_page == -1) {
3818802ae45eSLaurent Vivier             return -errno;
3819802ae45eSLaurent Vivier         }
3820802ae45eSLaurent Vivier 
3821db2af69dSRichard Henderson         setup_sigtramp(tramp_page);
3822db2af69dSRichard Henderson         target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
3823db2af69dSRichard Henderson     }
3824db2af69dSRichard Henderson 
382540d487eeSRichard Henderson     bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &ehdr,
38268e62a717SRichard Henderson                                 info, (elf_interpreter ? &interp_info : NULL));
38278e62a717SRichard Henderson     info->start_stack = bprm->p;
38288e62a717SRichard Henderson 
38298e62a717SRichard Henderson     /* If we have an interpreter, set that as the program's entry point.
38308e78064eSRichard Henderson        Copy the load_bias as well, to help PPC64 interpret the entry
38318e62a717SRichard Henderson        point as a function descriptor.  Do this after creating elf tables
38328e62a717SRichard Henderson        so that we copy the original program entry point into the AUXV.  */
38338e62a717SRichard Henderson     if (elf_interpreter) {
38348e78064eSRichard Henderson         info->load_bias = interp_info.load_bias;
38358e62a717SRichard Henderson         info->entry = interp_info.entry;
38362b323087SPhilippe Mathieu-Daudé         g_free(elf_interpreter);
38378e62a717SRichard Henderson     }
383831e31b8aSbellard 
3839edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3840edf8e2afSMika Westerberg     bprm->core_dump = &elf_core_dump;
3841edf8e2afSMika Westerberg #endif
3842edf8e2afSMika Westerberg 
384331e31b8aSbellard     return 0;
384431e31b8aSbellard }
384531e31b8aSbellard 
3846edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3847edf8e2afSMika Westerberg /*
3848edf8e2afSMika Westerberg  * Definitions to generate Intel SVR4-like core files.
3849a2547a13SLaurent Desnogues  * These mostly have the same names as the SVR4 types with "target_elf_"
3850edf8e2afSMika Westerberg  * tacked on the front to prevent clashes with linux definitions,
3851edf8e2afSMika Westerberg  * and the typedef forms have been avoided.  This is mostly like
3852edf8e2afSMika Westerberg  * the SVR4 structure, but more Linuxy, with things that Linux does
3853edf8e2afSMika Westerberg  * not support and which gdb doesn't really use excluded.
3854edf8e2afSMika Westerberg  *
3855edf8e2afSMika Westerberg  * Fields we don't dump (their contents is zero) in linux-user qemu
3856edf8e2afSMika Westerberg  * are marked with XXX.
3857edf8e2afSMika Westerberg  *
3858edf8e2afSMika Westerberg  * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
3859edf8e2afSMika Westerberg  *
3860edf8e2afSMika Westerberg  * Porting ELF coredump for target is (quite) simple process.  First you
3861dd0a3651SNathan Froyd  * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
3862edf8e2afSMika Westerberg  * the target resides):
3863edf8e2afSMika Westerberg  *
3864edf8e2afSMika Westerberg  * #define USE_ELF_CORE_DUMP
3865edf8e2afSMika Westerberg  *
3866edf8e2afSMika Westerberg  * Next you define type of register set used for dumping.  ELF specification
3867edf8e2afSMika Westerberg  * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
3868edf8e2afSMika Westerberg  *
3869c227f099SAnthony Liguori  * typedef <target_regtype> target_elf_greg_t;
3870edf8e2afSMika Westerberg  * #define ELF_NREG <number of registers>
3871c227f099SAnthony Liguori  * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
3872edf8e2afSMika Westerberg  *
3873edf8e2afSMika Westerberg  * Last step is to implement target specific function that copies registers
3874edf8e2afSMika Westerberg  * from given cpu into just specified register set.  Prototype is:
3875edf8e2afSMika Westerberg  *
3876c227f099SAnthony Liguori  * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
38779349b4f9SAndreas Färber  *                                const CPUArchState *env);
3878edf8e2afSMika Westerberg  *
3879edf8e2afSMika Westerberg  * Parameters:
3880edf8e2afSMika Westerberg  *     regs - copy register values into here (allocated and zeroed by caller)
3881edf8e2afSMika Westerberg  *     env - copy registers from here
3882edf8e2afSMika Westerberg  *
3883edf8e2afSMika Westerberg  * Example for ARM target is provided in this file.
3884edf8e2afSMika Westerberg  */
3885edf8e2afSMika Westerberg 
3886edf8e2afSMika Westerberg /* An ELF note in memory */
3887edf8e2afSMika Westerberg struct memelfnote {
3888edf8e2afSMika Westerberg     const char *name;
3889edf8e2afSMika Westerberg     size_t     namesz;
3890edf8e2afSMika Westerberg     size_t     namesz_rounded;
3891edf8e2afSMika Westerberg     int        type;
3892edf8e2afSMika Westerberg     size_t     datasz;
389380f5ce75SLaurent Vivier     size_t     datasz_rounded;
3894edf8e2afSMika Westerberg     void       *data;
3895edf8e2afSMika Westerberg     size_t     notesz;
3896edf8e2afSMika Westerberg };
3897edf8e2afSMika Westerberg 
3898a2547a13SLaurent Desnogues struct target_elf_siginfo {
3899f8fd4fc4SPaolo Bonzini     abi_int    si_signo; /* signal number */
3900f8fd4fc4SPaolo Bonzini     abi_int    si_code;  /* extra code */
3901f8fd4fc4SPaolo Bonzini     abi_int    si_errno; /* errno */
3902edf8e2afSMika Westerberg };
3903edf8e2afSMika Westerberg 
3904a2547a13SLaurent Desnogues struct target_elf_prstatus {
3905a2547a13SLaurent Desnogues     struct target_elf_siginfo pr_info;      /* Info associated with signal */
39061ddd592fSPaolo Bonzini     abi_short          pr_cursig;    /* Current signal */
3907ca98ac83SPaolo Bonzini     abi_ulong          pr_sigpend;   /* XXX */
3908ca98ac83SPaolo Bonzini     abi_ulong          pr_sighold;   /* XXX */
3909c227f099SAnthony Liguori     target_pid_t       pr_pid;
3910c227f099SAnthony Liguori     target_pid_t       pr_ppid;
3911c227f099SAnthony Liguori     target_pid_t       pr_pgrp;
3912c227f099SAnthony Liguori     target_pid_t       pr_sid;
3913edf8e2afSMika Westerberg     struct target_timeval pr_utime;  /* XXX User time */
3914edf8e2afSMika Westerberg     struct target_timeval pr_stime;  /* XXX System time */
3915edf8e2afSMika Westerberg     struct target_timeval pr_cutime; /* XXX Cumulative user time */
3916edf8e2afSMika Westerberg     struct target_timeval pr_cstime; /* XXX Cumulative system time */
3917c227f099SAnthony Liguori     target_elf_gregset_t      pr_reg;       /* GP registers */
3918f8fd4fc4SPaolo Bonzini     abi_int            pr_fpvalid;   /* XXX */
3919edf8e2afSMika Westerberg };
3920edf8e2afSMika Westerberg 
3921edf8e2afSMika Westerberg #define ELF_PRARGSZ     (80) /* Number of chars for args */
3922edf8e2afSMika Westerberg 
3923a2547a13SLaurent Desnogues struct target_elf_prpsinfo {
3924edf8e2afSMika Westerberg     char         pr_state;       /* numeric process state */
3925edf8e2afSMika Westerberg     char         pr_sname;       /* char for pr_state */
3926edf8e2afSMika Westerberg     char         pr_zomb;        /* zombie */
3927edf8e2afSMika Westerberg     char         pr_nice;        /* nice val */
3928ca98ac83SPaolo Bonzini     abi_ulong    pr_flag;        /* flags */
3929c227f099SAnthony Liguori     target_uid_t pr_uid;
3930c227f099SAnthony Liguori     target_gid_t pr_gid;
3931c227f099SAnthony Liguori     target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
3932edf8e2afSMika Westerberg     /* Lots missing */
3933d7eb2b92SAlistair Francis     char    pr_fname[16] QEMU_NONSTRING; /* filename of executable */
3934edf8e2afSMika Westerberg     char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
3935edf8e2afSMika Westerberg };
3936edf8e2afSMika Westerberg 
3937edf8e2afSMika Westerberg /* Here is the structure in which status of each thread is captured. */
3938edf8e2afSMika Westerberg struct elf_thread_status {
393972cf2d4fSBlue Swirl     QTAILQ_ENTRY(elf_thread_status)  ets_link;
3940a2547a13SLaurent Desnogues     struct target_elf_prstatus prstatus;   /* NT_PRSTATUS */
3941edf8e2afSMika Westerberg #if 0
3942edf8e2afSMika Westerberg     elf_fpregset_t fpu;             /* NT_PRFPREG */
3943edf8e2afSMika Westerberg     struct task_struct *thread;
3944edf8e2afSMika Westerberg     elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
3945edf8e2afSMika Westerberg #endif
3946edf8e2afSMika Westerberg     struct memelfnote notes[1];
3947edf8e2afSMika Westerberg     int num_notes;
3948edf8e2afSMika Westerberg };
3949edf8e2afSMika Westerberg 
3950edf8e2afSMika Westerberg struct elf_note_info {
3951edf8e2afSMika Westerberg     struct memelfnote   *notes;
3952a2547a13SLaurent Desnogues     struct target_elf_prstatus *prstatus;  /* NT_PRSTATUS */
3953a2547a13SLaurent Desnogues     struct target_elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
3954edf8e2afSMika Westerberg 
3955b58deb34SPaolo Bonzini     QTAILQ_HEAD(, elf_thread_status) thread_list;
3956edf8e2afSMika Westerberg #if 0
3957edf8e2afSMika Westerberg     /*
3958edf8e2afSMika Westerberg      * Current version of ELF coredump doesn't support
3959edf8e2afSMika Westerberg      * dumping fp regs etc.
3960edf8e2afSMika Westerberg      */
3961edf8e2afSMika Westerberg     elf_fpregset_t *fpu;
3962edf8e2afSMika Westerberg     elf_fpxregset_t *xfpu;
3963edf8e2afSMika Westerberg     int thread_status_size;
3964edf8e2afSMika Westerberg #endif
3965edf8e2afSMika Westerberg     int notes_size;
3966edf8e2afSMika Westerberg     int numnote;
3967edf8e2afSMika Westerberg };
3968edf8e2afSMika Westerberg 
3969edf8e2afSMika Westerberg struct vm_area_struct {
39701a1c4db9SMikhail Ilyin     target_ulong   vma_start;  /* start vaddr of memory region */
39711a1c4db9SMikhail Ilyin     target_ulong   vma_end;    /* end vaddr of memory region */
3972edf8e2afSMika Westerberg     abi_ulong      vma_flags;  /* protection etc. flags for the region */
397372cf2d4fSBlue Swirl     QTAILQ_ENTRY(vm_area_struct) vma_link;
3974edf8e2afSMika Westerberg };
3975edf8e2afSMika Westerberg 
3976edf8e2afSMika Westerberg struct mm_struct {
397772cf2d4fSBlue Swirl     QTAILQ_HEAD(, vm_area_struct) mm_mmap;
3978edf8e2afSMika Westerberg     int mm_count;           /* number of mappings */
3979edf8e2afSMika Westerberg };
3980edf8e2afSMika Westerberg 
3981edf8e2afSMika Westerberg static struct mm_struct *vma_init(void);
3982edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *);
39831a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *, target_ulong,
39841a1c4db9SMikhail Ilyin                            target_ulong, abi_ulong);
3985edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *);
3986edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *);
3987edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *);
3988edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *);
39891a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
3990edf8e2afSMika Westerberg                       unsigned long flags);
3991edf8e2afSMika Westerberg 
3992edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
3993edf8e2afSMika Westerberg static void fill_note(struct memelfnote *, const char *, int,
3994edf8e2afSMika Westerberg                       unsigned int, void *);
3995a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
3996a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
3997edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *, const TaskState *);
3998edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
3999edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *);
4000edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *);
40019349b4f9SAndreas Färber static int fill_note_info(struct elf_note_info *, long, const CPUArchState *);
40029349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *, const CPUArchState *);
4003edf8e2afSMika Westerberg 
4004edf8e2afSMika Westerberg static int dump_write(int, const void *, size_t);
4005edf8e2afSMika Westerberg static int write_note(struct memelfnote *, int);
4006edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *, int);
4007edf8e2afSMika Westerberg 
4008edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
4009a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *prstatus)
4010edf8e2afSMika Westerberg {
4011ca98ac83SPaolo Bonzini     prstatus->pr_info.si_signo = tswap32(prstatus->pr_info.si_signo);
4012ca98ac83SPaolo Bonzini     prstatus->pr_info.si_code = tswap32(prstatus->pr_info.si_code);
4013ca98ac83SPaolo Bonzini     prstatus->pr_info.si_errno = tswap32(prstatus->pr_info.si_errno);
4014edf8e2afSMika Westerberg     prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
4015ca98ac83SPaolo Bonzini     prstatus->pr_sigpend = tswapal(prstatus->pr_sigpend);
4016ca98ac83SPaolo Bonzini     prstatus->pr_sighold = tswapal(prstatus->pr_sighold);
4017edf8e2afSMika Westerberg     prstatus->pr_pid = tswap32(prstatus->pr_pid);
4018edf8e2afSMika Westerberg     prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
4019edf8e2afSMika Westerberg     prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
4020edf8e2afSMika Westerberg     prstatus->pr_sid = tswap32(prstatus->pr_sid);
4021edf8e2afSMika Westerberg     /* cpu times are not filled, so we skip them */
4022edf8e2afSMika Westerberg     /* regs should be in correct format already */
4023edf8e2afSMika Westerberg     prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
4024edf8e2afSMika Westerberg }
4025edf8e2afSMika Westerberg 
4026a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
4027edf8e2afSMika Westerberg {
4028ca98ac83SPaolo Bonzini     psinfo->pr_flag = tswapal(psinfo->pr_flag);
4029edf8e2afSMika Westerberg     psinfo->pr_uid = tswap16(psinfo->pr_uid);
4030edf8e2afSMika Westerberg     psinfo->pr_gid = tswap16(psinfo->pr_gid);
4031edf8e2afSMika Westerberg     psinfo->pr_pid = tswap32(psinfo->pr_pid);
4032edf8e2afSMika Westerberg     psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
4033edf8e2afSMika Westerberg     psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
4034edf8e2afSMika Westerberg     psinfo->pr_sid = tswap32(psinfo->pr_sid);
4035edf8e2afSMika Westerberg }
4036991f8f0cSRichard Henderson 
4037991f8f0cSRichard Henderson static void bswap_note(struct elf_note *en)
4038991f8f0cSRichard Henderson {
4039991f8f0cSRichard Henderson     bswap32s(&en->n_namesz);
4040991f8f0cSRichard Henderson     bswap32s(&en->n_descsz);
4041991f8f0cSRichard Henderson     bswap32s(&en->n_type);
4042991f8f0cSRichard Henderson }
4043991f8f0cSRichard Henderson #else
4044991f8f0cSRichard Henderson static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
4045991f8f0cSRichard Henderson static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
4046991f8f0cSRichard Henderson static inline void bswap_note(struct elf_note *en) { }
4047edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
4048edf8e2afSMika Westerberg 
4049edf8e2afSMika Westerberg /*
4050edf8e2afSMika Westerberg  * Minimal support for linux memory regions.  These are needed
4051edf8e2afSMika Westerberg  * when we are finding out what memory exactly belongs to
4052edf8e2afSMika Westerberg  * emulated process.  No locks needed here, as long as
4053edf8e2afSMika Westerberg  * thread that received the signal is stopped.
4054edf8e2afSMika Westerberg  */
4055edf8e2afSMika Westerberg 
4056edf8e2afSMika Westerberg static struct mm_struct *vma_init(void)
4057edf8e2afSMika Westerberg {
4058edf8e2afSMika Westerberg     struct mm_struct *mm;
4059edf8e2afSMika Westerberg 
40607267c094SAnthony Liguori     if ((mm = g_malloc(sizeof (*mm))) == NULL)
4061edf8e2afSMika Westerberg         return (NULL);
4062edf8e2afSMika Westerberg 
4063edf8e2afSMika Westerberg     mm->mm_count = 0;
406472cf2d4fSBlue Swirl     QTAILQ_INIT(&mm->mm_mmap);
4065edf8e2afSMika Westerberg 
4066edf8e2afSMika Westerberg     return (mm);
4067edf8e2afSMika Westerberg }
4068edf8e2afSMika Westerberg 
4069edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *mm)
4070edf8e2afSMika Westerberg {
4071edf8e2afSMika Westerberg     struct vm_area_struct *vma;
4072edf8e2afSMika Westerberg 
4073edf8e2afSMika Westerberg     while ((vma = vma_first(mm)) != NULL) {
407472cf2d4fSBlue Swirl         QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
40757267c094SAnthony Liguori         g_free(vma);
4076edf8e2afSMika Westerberg     }
40777267c094SAnthony Liguori     g_free(mm);
4078edf8e2afSMika Westerberg }
4079edf8e2afSMika Westerberg 
40801a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *mm, target_ulong start,
40811a1c4db9SMikhail Ilyin                            target_ulong end, abi_ulong flags)
4082edf8e2afSMika Westerberg {
4083edf8e2afSMika Westerberg     struct vm_area_struct *vma;
4084edf8e2afSMika Westerberg 
40857267c094SAnthony Liguori     if ((vma = g_malloc0(sizeof (*vma))) == NULL)
4086edf8e2afSMika Westerberg         return (-1);
4087edf8e2afSMika Westerberg 
4088edf8e2afSMika Westerberg     vma->vma_start = start;
4089edf8e2afSMika Westerberg     vma->vma_end = end;
4090edf8e2afSMika Westerberg     vma->vma_flags = flags;
4091edf8e2afSMika Westerberg 
409272cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
4093edf8e2afSMika Westerberg     mm->mm_count++;
4094edf8e2afSMika Westerberg 
4095edf8e2afSMika Westerberg     return (0);
4096edf8e2afSMika Westerberg }
4097edf8e2afSMika Westerberg 
4098edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *mm)
4099edf8e2afSMika Westerberg {
410072cf2d4fSBlue Swirl     return (QTAILQ_FIRST(&mm->mm_mmap));
4101edf8e2afSMika Westerberg }
4102edf8e2afSMika Westerberg 
4103edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
4104edf8e2afSMika Westerberg {
410572cf2d4fSBlue Swirl     return (QTAILQ_NEXT(vma, vma_link));
4106edf8e2afSMika Westerberg }
4107edf8e2afSMika Westerberg 
4108edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *mm)
4109edf8e2afSMika Westerberg {
4110edf8e2afSMika Westerberg     return (mm->mm_count);
4111edf8e2afSMika Westerberg }
4112edf8e2afSMika Westerberg 
4113edf8e2afSMika Westerberg /*
4114edf8e2afSMika Westerberg  * Calculate file (dump) size of given memory region.
4115edf8e2afSMika Westerberg  */
4116edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
4117edf8e2afSMika Westerberg {
4118edf8e2afSMika Westerberg     /* if we cannot even read the first page, skip it */
4119c7169b02SRichard Henderson     if (!access_ok_untagged(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
4120edf8e2afSMika Westerberg         return (0);
4121edf8e2afSMika Westerberg 
4122edf8e2afSMika Westerberg     /*
4123edf8e2afSMika Westerberg      * Usually we don't dump executable pages as they contain
4124edf8e2afSMika Westerberg      * non-writable code that debugger can read directly from
4125edf8e2afSMika Westerberg      * target library etc.  However, thread stacks are marked
4126edf8e2afSMika Westerberg      * also executable so we read in first page of given region
4127edf8e2afSMika Westerberg      * and check whether it contains elf header.  If there is
4128edf8e2afSMika Westerberg      * no elf header, we dump it.
4129edf8e2afSMika Westerberg      */
4130edf8e2afSMika Westerberg     if (vma->vma_flags & PROT_EXEC) {
4131edf8e2afSMika Westerberg         char page[TARGET_PAGE_SIZE];
4132edf8e2afSMika Westerberg 
4133022625a8SPeter Maydell         if (copy_from_user(page, vma->vma_start, sizeof (page))) {
4134022625a8SPeter Maydell             return 0;
4135022625a8SPeter Maydell         }
4136edf8e2afSMika Westerberg         if ((page[EI_MAG0] == ELFMAG0) &&
4137edf8e2afSMika Westerberg             (page[EI_MAG1] == ELFMAG1) &&
4138edf8e2afSMika Westerberg             (page[EI_MAG2] == ELFMAG2) &&
4139edf8e2afSMika Westerberg             (page[EI_MAG3] == ELFMAG3)) {
4140edf8e2afSMika Westerberg             /*
4141edf8e2afSMika Westerberg              * Mappings are possibly from ELF binary.  Don't dump
4142edf8e2afSMika Westerberg              * them.
4143edf8e2afSMika Westerberg              */
4144edf8e2afSMika Westerberg             return (0);
4145edf8e2afSMika Westerberg         }
4146edf8e2afSMika Westerberg     }
4147edf8e2afSMika Westerberg 
4148edf8e2afSMika Westerberg     return (vma->vma_end - vma->vma_start);
4149edf8e2afSMika Westerberg }
4150edf8e2afSMika Westerberg 
41511a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
4152edf8e2afSMika Westerberg                       unsigned long flags)
4153edf8e2afSMika Westerberg {
4154edf8e2afSMika Westerberg     struct mm_struct *mm = (struct mm_struct *)priv;
4155edf8e2afSMika Westerberg 
4156edf8e2afSMika Westerberg     vma_add_mapping(mm, start, end, flags);
4157edf8e2afSMika Westerberg     return (0);
4158edf8e2afSMika Westerberg }
4159edf8e2afSMika Westerberg 
4160edf8e2afSMika Westerberg static void fill_note(struct memelfnote *note, const char *name, int type,
4161edf8e2afSMika Westerberg                       unsigned int sz, void *data)
4162edf8e2afSMika Westerberg {
4163edf8e2afSMika Westerberg     unsigned int namesz;
4164edf8e2afSMika Westerberg 
4165edf8e2afSMika Westerberg     namesz = strlen(name) + 1;
4166edf8e2afSMika Westerberg     note->name = name;
4167edf8e2afSMika Westerberg     note->namesz = namesz;
4168edf8e2afSMika Westerberg     note->namesz_rounded = roundup(namesz, sizeof (int32_t));
4169edf8e2afSMika Westerberg     note->type = type;
417080f5ce75SLaurent Vivier     note->datasz = sz;
417180f5ce75SLaurent Vivier     note->datasz_rounded = roundup(sz, sizeof (int32_t));
417280f5ce75SLaurent Vivier 
4173edf8e2afSMika Westerberg     note->data = data;
4174edf8e2afSMika Westerberg 
4175edf8e2afSMika Westerberg     /*
4176edf8e2afSMika Westerberg      * We calculate rounded up note size here as specified by
4177edf8e2afSMika Westerberg      * ELF document.
4178edf8e2afSMika Westerberg      */
4179edf8e2afSMika Westerberg     note->notesz = sizeof (struct elf_note) +
418080f5ce75SLaurent Vivier         note->namesz_rounded + note->datasz_rounded;
4181edf8e2afSMika Westerberg }
4182edf8e2afSMika Westerberg 
4183edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
4184edf8e2afSMika Westerberg                             uint32_t flags)
4185edf8e2afSMika Westerberg {
4186edf8e2afSMika Westerberg     (void) memset(elf, 0, sizeof(*elf));
4187edf8e2afSMika Westerberg 
4188edf8e2afSMika Westerberg     (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
4189edf8e2afSMika Westerberg     elf->e_ident[EI_CLASS] = ELF_CLASS;
4190edf8e2afSMika Westerberg     elf->e_ident[EI_DATA] = ELF_DATA;
4191edf8e2afSMika Westerberg     elf->e_ident[EI_VERSION] = EV_CURRENT;
4192edf8e2afSMika Westerberg     elf->e_ident[EI_OSABI] = ELF_OSABI;
4193edf8e2afSMika Westerberg 
4194edf8e2afSMika Westerberg     elf->e_type = ET_CORE;
4195edf8e2afSMika Westerberg     elf->e_machine = machine;
4196edf8e2afSMika Westerberg     elf->e_version = EV_CURRENT;
4197edf8e2afSMika Westerberg     elf->e_phoff = sizeof(struct elfhdr);
4198edf8e2afSMika Westerberg     elf->e_flags = flags;
4199edf8e2afSMika Westerberg     elf->e_ehsize = sizeof(struct elfhdr);
4200edf8e2afSMika Westerberg     elf->e_phentsize = sizeof(struct elf_phdr);
4201edf8e2afSMika Westerberg     elf->e_phnum = segs;
4202edf8e2afSMika Westerberg 
4203edf8e2afSMika Westerberg     bswap_ehdr(elf);
4204edf8e2afSMika Westerberg }
4205edf8e2afSMika Westerberg 
4206edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
4207edf8e2afSMika Westerberg {
4208edf8e2afSMika Westerberg     phdr->p_type = PT_NOTE;
4209edf8e2afSMika Westerberg     phdr->p_offset = offset;
4210edf8e2afSMika Westerberg     phdr->p_vaddr = 0;
4211edf8e2afSMika Westerberg     phdr->p_paddr = 0;
4212edf8e2afSMika Westerberg     phdr->p_filesz = sz;
4213edf8e2afSMika Westerberg     phdr->p_memsz = 0;
4214edf8e2afSMika Westerberg     phdr->p_flags = 0;
4215edf8e2afSMika Westerberg     phdr->p_align = 0;
4216edf8e2afSMika Westerberg 
4217991f8f0cSRichard Henderson     bswap_phdr(phdr, 1);
4218edf8e2afSMika Westerberg }
4219edf8e2afSMika Westerberg 
4220edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *note)
4221edf8e2afSMika Westerberg {
4222edf8e2afSMika Westerberg     return (note->notesz);
4223edf8e2afSMika Westerberg }
4224edf8e2afSMika Westerberg 
4225a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *prstatus,
4226edf8e2afSMika Westerberg                           const TaskState *ts, int signr)
4227edf8e2afSMika Westerberg {
4228edf8e2afSMika Westerberg     (void) memset(prstatus, 0, sizeof (*prstatus));
4229edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
4230edf8e2afSMika Westerberg     prstatus->pr_pid = ts->ts_tid;
4231edf8e2afSMika Westerberg     prstatus->pr_ppid = getppid();
4232edf8e2afSMika Westerberg     prstatus->pr_pgrp = getpgrp();
4233edf8e2afSMika Westerberg     prstatus->pr_sid = getsid(0);
4234edf8e2afSMika Westerberg 
4235edf8e2afSMika Westerberg     bswap_prstatus(prstatus);
4236edf8e2afSMika Westerberg }
4237edf8e2afSMika Westerberg 
4238a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
4239edf8e2afSMika Westerberg {
4240900cfbcaSJim Meyering     char *base_filename;
4241edf8e2afSMika Westerberg     unsigned int i, len;
4242edf8e2afSMika Westerberg 
4243edf8e2afSMika Westerberg     (void) memset(psinfo, 0, sizeof (*psinfo));
4244edf8e2afSMika Westerberg 
42455f779a3aSIlya Leoshkevich     len = ts->info->env_strings - ts->info->arg_strings;
4246edf8e2afSMika Westerberg     if (len >= ELF_PRARGSZ)
4247edf8e2afSMika Westerberg         len = ELF_PRARGSZ - 1;
42485f779a3aSIlya Leoshkevich     if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_strings, len)) {
4249edf8e2afSMika Westerberg         return -EFAULT;
42505f779a3aSIlya Leoshkevich     }
4251edf8e2afSMika Westerberg     for (i = 0; i < len; i++)
4252edf8e2afSMika Westerberg         if (psinfo->pr_psargs[i] == 0)
4253edf8e2afSMika Westerberg             psinfo->pr_psargs[i] = ' ';
4254edf8e2afSMika Westerberg     psinfo->pr_psargs[len] = 0;
4255edf8e2afSMika Westerberg 
4256edf8e2afSMika Westerberg     psinfo->pr_pid = getpid();
4257edf8e2afSMika Westerberg     psinfo->pr_ppid = getppid();
4258edf8e2afSMika Westerberg     psinfo->pr_pgrp = getpgrp();
4259edf8e2afSMika Westerberg     psinfo->pr_sid = getsid(0);
4260edf8e2afSMika Westerberg     psinfo->pr_uid = getuid();
4261edf8e2afSMika Westerberg     psinfo->pr_gid = getgid();
4262edf8e2afSMika Westerberg 
4263900cfbcaSJim Meyering     base_filename = g_path_get_basename(ts->bprm->filename);
4264900cfbcaSJim Meyering     /*
4265900cfbcaSJim Meyering      * Using strncpy here is fine: at max-length,
4266900cfbcaSJim Meyering      * this field is not NUL-terminated.
4267900cfbcaSJim Meyering      */
4268edf8e2afSMika Westerberg     (void) strncpy(psinfo->pr_fname, base_filename,
4269edf8e2afSMika Westerberg                    sizeof(psinfo->pr_fname));
4270edf8e2afSMika Westerberg 
4271900cfbcaSJim Meyering     g_free(base_filename);
4272edf8e2afSMika Westerberg     bswap_psinfo(psinfo);
4273edf8e2afSMika Westerberg     return (0);
4274edf8e2afSMika Westerberg }
4275edf8e2afSMika Westerberg 
4276edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
4277edf8e2afSMika Westerberg {
4278edf8e2afSMika Westerberg     elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
4279edf8e2afSMika Westerberg     elf_addr_t orig_auxv = auxv;
4280edf8e2afSMika Westerberg     void *ptr;
4281125b0f55SAlexander Graf     int len = ts->info->auxv_len;
4282edf8e2afSMika Westerberg 
4283edf8e2afSMika Westerberg     /*
4284edf8e2afSMika Westerberg      * Auxiliary vector is stored in target process stack.  It contains
4285edf8e2afSMika Westerberg      * {type, value} pairs that we need to dump into note.  This is not
4286edf8e2afSMika Westerberg      * strictly necessary but we do it here for sake of completeness.
4287edf8e2afSMika Westerberg      */
4288edf8e2afSMika Westerberg 
4289edf8e2afSMika Westerberg     /* read in whole auxv vector and copy it to memelfnote */
4290edf8e2afSMika Westerberg     ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
4291edf8e2afSMika Westerberg     if (ptr != NULL) {
4292edf8e2afSMika Westerberg         fill_note(note, "CORE", NT_AUXV, len, ptr);
4293edf8e2afSMika Westerberg         unlock_user(ptr, auxv, len);
4294edf8e2afSMika Westerberg     }
4295edf8e2afSMika Westerberg }
4296edf8e2afSMika Westerberg 
4297edf8e2afSMika Westerberg /*
4298edf8e2afSMika Westerberg  * Constructs name of coredump file.  We have following convention
4299edf8e2afSMika Westerberg  * for the name:
4300edf8e2afSMika Westerberg  *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
4301edf8e2afSMika Westerberg  *
430268af19adSDaniel P. Berrangé  * Returns the filename
4303edf8e2afSMika Westerberg  */
430468af19adSDaniel P. Berrangé static char *core_dump_filename(const TaskState *ts)
4305edf8e2afSMika Westerberg {
430668af19adSDaniel P. Berrangé     g_autoptr(GDateTime) now = g_date_time_new_now_local();
430768af19adSDaniel P. Berrangé     g_autofree char *nowstr = g_date_time_format(now, "%Y%m%d-%H%M%S");
430868af19adSDaniel P. Berrangé     g_autofree char *base_filename = g_path_get_basename(ts->bprm->filename);
4309edf8e2afSMika Westerberg 
431068af19adSDaniel P. Berrangé     return g_strdup_printf("qemu_%s_%s_%d.core",
431168af19adSDaniel P. Berrangé                            base_filename, nowstr, (int)getpid());
4312edf8e2afSMika Westerberg }
4313edf8e2afSMika Westerberg 
4314edf8e2afSMika Westerberg static int dump_write(int fd, const void *ptr, size_t size)
4315edf8e2afSMika Westerberg {
4316edf8e2afSMika Westerberg     const char *bufp = (const char *)ptr;
4317edf8e2afSMika Westerberg     ssize_t bytes_written, bytes_left;
4318edf8e2afSMika Westerberg     struct rlimit dumpsize;
4319edf8e2afSMika Westerberg     off_t pos;
4320edf8e2afSMika Westerberg 
4321edf8e2afSMika Westerberg     bytes_written = 0;
4322edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
4323edf8e2afSMika Westerberg     if ((pos = lseek(fd, 0, SEEK_CUR))==-1) {
4324edf8e2afSMika Westerberg         if (errno == ESPIPE) { /* not a seekable stream */
4325edf8e2afSMika Westerberg             bytes_left = size;
4326edf8e2afSMika Westerberg         } else {
4327edf8e2afSMika Westerberg             return pos;
4328edf8e2afSMika Westerberg         }
4329edf8e2afSMika Westerberg     } else {
4330edf8e2afSMika Westerberg         if (dumpsize.rlim_cur <= pos) {
4331edf8e2afSMika Westerberg             return -1;
4332edf8e2afSMika Westerberg         } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
4333edf8e2afSMika Westerberg             bytes_left = size;
4334edf8e2afSMika Westerberg         } else {
4335edf8e2afSMika Westerberg             size_t limit_left=dumpsize.rlim_cur - pos;
4336edf8e2afSMika Westerberg             bytes_left = limit_left >= size ? size : limit_left ;
4337edf8e2afSMika Westerberg         }
4338edf8e2afSMika Westerberg     }
4339edf8e2afSMika Westerberg 
4340edf8e2afSMika Westerberg     /*
4341edf8e2afSMika Westerberg      * In normal conditions, single write(2) should do but
4342edf8e2afSMika Westerberg      * in case of socket etc. this mechanism is more portable.
4343edf8e2afSMika Westerberg      */
4344edf8e2afSMika Westerberg     do {
4345edf8e2afSMika Westerberg         bytes_written = write(fd, bufp, bytes_left);
4346edf8e2afSMika Westerberg         if (bytes_written < 0) {
4347edf8e2afSMika Westerberg             if (errno == EINTR)
4348edf8e2afSMika Westerberg                 continue;
4349edf8e2afSMika Westerberg             return (-1);
4350edf8e2afSMika Westerberg         } else if (bytes_written == 0) { /* eof */
4351edf8e2afSMika Westerberg             return (-1);
4352edf8e2afSMika Westerberg         }
4353edf8e2afSMika Westerberg         bufp += bytes_written;
4354edf8e2afSMika Westerberg         bytes_left -= bytes_written;
4355edf8e2afSMika Westerberg     } while (bytes_left > 0);
4356edf8e2afSMika Westerberg 
4357edf8e2afSMika Westerberg     return (0);
4358edf8e2afSMika Westerberg }
4359edf8e2afSMika Westerberg 
4360edf8e2afSMika Westerberg static int write_note(struct memelfnote *men, int fd)
4361edf8e2afSMika Westerberg {
4362edf8e2afSMika Westerberg     struct elf_note en;
4363edf8e2afSMika Westerberg 
4364edf8e2afSMika Westerberg     en.n_namesz = men->namesz;
4365edf8e2afSMika Westerberg     en.n_type = men->type;
4366edf8e2afSMika Westerberg     en.n_descsz = men->datasz;
4367edf8e2afSMika Westerberg 
4368edf8e2afSMika Westerberg     bswap_note(&en);
4369edf8e2afSMika Westerberg 
4370edf8e2afSMika Westerberg     if (dump_write(fd, &en, sizeof(en)) != 0)
4371edf8e2afSMika Westerberg         return (-1);
4372edf8e2afSMika Westerberg     if (dump_write(fd, men->name, men->namesz_rounded) != 0)
4373edf8e2afSMika Westerberg         return (-1);
437480f5ce75SLaurent Vivier     if (dump_write(fd, men->data, men->datasz_rounded) != 0)
4375edf8e2afSMika Westerberg         return (-1);
4376edf8e2afSMika Westerberg 
4377edf8e2afSMika Westerberg     return (0);
4378edf8e2afSMika Westerberg }
4379edf8e2afSMika Westerberg 
43809349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *info, const CPUArchState *env)
4381edf8e2afSMika Westerberg {
438229a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
43830429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4384edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4385edf8e2afSMika Westerberg 
43867267c094SAnthony Liguori     ets = g_malloc0(sizeof (*ets));
4387edf8e2afSMika Westerberg     ets->num_notes = 1; /* only prstatus is dumped */
4388edf8e2afSMika Westerberg     fill_prstatus(&ets->prstatus, ts, 0);
4389edf8e2afSMika Westerberg     elf_core_copy_regs(&ets->prstatus.pr_reg, env);
4390edf8e2afSMika Westerberg     fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
4391edf8e2afSMika Westerberg               &ets->prstatus);
4392edf8e2afSMika Westerberg 
439372cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
4394edf8e2afSMika Westerberg 
4395edf8e2afSMika Westerberg     info->notes_size += note_size(&ets->notes[0]);
4396edf8e2afSMika Westerberg }
4397edf8e2afSMika Westerberg 
43986afafa86SPeter Maydell static void init_note_info(struct elf_note_info *info)
43996afafa86SPeter Maydell {
44006afafa86SPeter Maydell     /* Initialize the elf_note_info structure so that it is at
44016afafa86SPeter Maydell      * least safe to call free_note_info() on it. Must be
44026afafa86SPeter Maydell      * called before calling fill_note_info().
44036afafa86SPeter Maydell      */
44046afafa86SPeter Maydell     memset(info, 0, sizeof (*info));
44056afafa86SPeter Maydell     QTAILQ_INIT(&info->thread_list);
44066afafa86SPeter Maydell }
44076afafa86SPeter Maydell 
4408edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *info,
44099349b4f9SAndreas Färber                           long signr, const CPUArchState *env)
4410edf8e2afSMika Westerberg {
4411edf8e2afSMika Westerberg #define NUMNOTES 3
441229a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
44130429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4414edf8e2afSMika Westerberg     int i;
4415edf8e2afSMika Westerberg 
4416c78d65e8SMarkus Armbruster     info->notes = g_new0(struct memelfnote, NUMNOTES);
4417edf8e2afSMika Westerberg     if (info->notes == NULL)
4418edf8e2afSMika Westerberg         return (-ENOMEM);
44197267c094SAnthony Liguori     info->prstatus = g_malloc0(sizeof (*info->prstatus));
4420edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4421edf8e2afSMika Westerberg         return (-ENOMEM);
44227267c094SAnthony Liguori     info->psinfo = g_malloc0(sizeof (*info->psinfo));
4423edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4424edf8e2afSMika Westerberg         return (-ENOMEM);
4425edf8e2afSMika Westerberg 
4426edf8e2afSMika Westerberg     /*
4427edf8e2afSMika Westerberg      * First fill in status (and registers) of current thread
4428edf8e2afSMika Westerberg      * including process info & aux vector.
4429edf8e2afSMika Westerberg      */
4430edf8e2afSMika Westerberg     fill_prstatus(info->prstatus, ts, signr);
4431edf8e2afSMika Westerberg     elf_core_copy_regs(&info->prstatus->pr_reg, env);
4432edf8e2afSMika Westerberg     fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
4433edf8e2afSMika Westerberg               sizeof (*info->prstatus), info->prstatus);
4434edf8e2afSMika Westerberg     fill_psinfo(info->psinfo, ts);
4435edf8e2afSMika Westerberg     fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
4436edf8e2afSMika Westerberg               sizeof (*info->psinfo), info->psinfo);
4437edf8e2afSMika Westerberg     fill_auxv_note(&info->notes[2], ts);
4438edf8e2afSMika Westerberg     info->numnote = 3;
4439edf8e2afSMika Westerberg 
4440edf8e2afSMika Westerberg     info->notes_size = 0;
4441edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4442edf8e2afSMika Westerberg         info->notes_size += note_size(&info->notes[i]);
4443edf8e2afSMika Westerberg 
4444edf8e2afSMika Westerberg     /* read and fill status of all threads */
4445370ed600SJamie Iles     WITH_QEMU_LOCK_GUARD(&qemu_cpu_list_lock) {
4446bdc44640SAndreas Färber         CPU_FOREACH(cpu) {
4447a2247f8eSAndreas Färber             if (cpu == thread_cpu) {
4448edf8e2afSMika Westerberg                 continue;
4449182735efSAndreas Färber             }
4450b77af26eSRichard Henderson             fill_thread_info(info, cpu_env(cpu));
4451edf8e2afSMika Westerberg         }
4452370ed600SJamie Iles     }
4453edf8e2afSMika Westerberg 
4454edf8e2afSMika Westerberg     return (0);
4455edf8e2afSMika Westerberg }
4456edf8e2afSMika Westerberg 
4457edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *info)
4458edf8e2afSMika Westerberg {
4459edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4460edf8e2afSMika Westerberg 
446172cf2d4fSBlue Swirl     while (!QTAILQ_EMPTY(&info->thread_list)) {
446272cf2d4fSBlue Swirl         ets = QTAILQ_FIRST(&info->thread_list);
446372cf2d4fSBlue Swirl         QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
44647267c094SAnthony Liguori         g_free(ets);
4465edf8e2afSMika Westerberg     }
4466edf8e2afSMika Westerberg 
44677267c094SAnthony Liguori     g_free(info->prstatus);
44687267c094SAnthony Liguori     g_free(info->psinfo);
44697267c094SAnthony Liguori     g_free(info->notes);
4470edf8e2afSMika Westerberg }
4471edf8e2afSMika Westerberg 
4472edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *info, int fd)
4473edf8e2afSMika Westerberg {
4474edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4475edf8e2afSMika Westerberg     int i, error = 0;
4476edf8e2afSMika Westerberg 
4477edf8e2afSMika Westerberg     /* write prstatus, psinfo and auxv for current thread */
4478edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4479edf8e2afSMika Westerberg         if ((error = write_note(&info->notes[i], fd)) != 0)
4480edf8e2afSMika Westerberg             return (error);
4481edf8e2afSMika Westerberg 
4482edf8e2afSMika Westerberg     /* write prstatus for each thread */
448352a53afeSEmilio G. Cota     QTAILQ_FOREACH(ets, &info->thread_list, ets_link) {
4484edf8e2afSMika Westerberg         if ((error = write_note(&ets->notes[0], fd)) != 0)
4485edf8e2afSMika Westerberg             return (error);
4486edf8e2afSMika Westerberg     }
4487edf8e2afSMika Westerberg 
4488edf8e2afSMika Westerberg     return (0);
4489edf8e2afSMika Westerberg }
4490edf8e2afSMika Westerberg 
4491edf8e2afSMika Westerberg /*
4492edf8e2afSMika Westerberg  * Write out ELF coredump.
4493edf8e2afSMika Westerberg  *
4494edf8e2afSMika Westerberg  * See documentation of ELF object file format in:
4495edf8e2afSMika Westerberg  * http://www.caldera.com/developers/devspecs/gabi41.pdf
4496edf8e2afSMika Westerberg  *
4497edf8e2afSMika Westerberg  * Coredump format in linux is following:
4498edf8e2afSMika Westerberg  *
4499edf8e2afSMika Westerberg  * 0   +----------------------+         \
4500edf8e2afSMika Westerberg  *     | ELF header           | ET_CORE  |
4501edf8e2afSMika Westerberg  *     +----------------------+          |
4502edf8e2afSMika Westerberg  *     | ELF program headers  |          |--- headers
4503edf8e2afSMika Westerberg  *     | - NOTE section       |          |
4504edf8e2afSMika Westerberg  *     | - PT_LOAD sections   |          |
4505edf8e2afSMika Westerberg  *     +----------------------+         /
4506edf8e2afSMika Westerberg  *     | NOTEs:               |
4507edf8e2afSMika Westerberg  *     | - NT_PRSTATUS        |
4508edf8e2afSMika Westerberg  *     | - NT_PRSINFO         |
4509edf8e2afSMika Westerberg  *     | - NT_AUXV            |
4510edf8e2afSMika Westerberg  *     +----------------------+ <-- aligned to target page
4511edf8e2afSMika Westerberg  *     | Process memory dump  |
4512edf8e2afSMika Westerberg  *     :                      :
4513edf8e2afSMika Westerberg  *     .                      .
4514edf8e2afSMika Westerberg  *     :                      :
4515edf8e2afSMika Westerberg  *     |                      |
4516edf8e2afSMika Westerberg  *     +----------------------+
4517edf8e2afSMika Westerberg  *
4518edf8e2afSMika Westerberg  * NT_PRSTATUS -> struct elf_prstatus (per thread)
4519edf8e2afSMika Westerberg  * NT_PRSINFO  -> struct elf_prpsinfo
4520edf8e2afSMika Westerberg  * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
4521edf8e2afSMika Westerberg  *
4522edf8e2afSMika Westerberg  * Format follows System V format as close as possible.  Current
4523edf8e2afSMika Westerberg  * version limitations are as follows:
4524edf8e2afSMika Westerberg  *     - no floating point registers are dumped
4525edf8e2afSMika Westerberg  *
4526edf8e2afSMika Westerberg  * Function returns 0 in case of success, negative errno otherwise.
4527edf8e2afSMika Westerberg  *
4528edf8e2afSMika Westerberg  * TODO: make this work also during runtime: it should be
4529edf8e2afSMika Westerberg  * possible to force coredump from running process and then
4530edf8e2afSMika Westerberg  * continue processing.  For example qemu could set up SIGUSR2
4531edf8e2afSMika Westerberg  * handler (provided that target process haven't registered
4532edf8e2afSMika Westerberg  * handler for that) that does the dump when signal is received.
4533edf8e2afSMika Westerberg  */
45349349b4f9SAndreas Färber static int elf_core_dump(int signr, const CPUArchState *env)
4535edf8e2afSMika Westerberg {
453629a0af61SRichard Henderson     const CPUState *cpu = env_cpu((CPUArchState *)env);
45370429a971SAndreas Färber     const TaskState *ts = (const TaskState *)cpu->opaque;
4538edf8e2afSMika Westerberg     struct vm_area_struct *vma = NULL;
453968af19adSDaniel P. Berrangé     g_autofree char *corefile = NULL;
4540edf8e2afSMika Westerberg     struct elf_note_info info;
4541edf8e2afSMika Westerberg     struct elfhdr elf;
4542edf8e2afSMika Westerberg     struct elf_phdr phdr;
4543edf8e2afSMika Westerberg     struct rlimit dumpsize;
4544edf8e2afSMika Westerberg     struct mm_struct *mm = NULL;
4545edf8e2afSMika Westerberg     off_t offset = 0, data_offset = 0;
4546edf8e2afSMika Westerberg     int segs = 0;
4547edf8e2afSMika Westerberg     int fd = -1;
4548edf8e2afSMika Westerberg 
45496afafa86SPeter Maydell     init_note_info(&info);
45506afafa86SPeter Maydell 
4551edf8e2afSMika Westerberg     errno = 0;
4552edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
4553edf8e2afSMika Westerberg     if (dumpsize.rlim_cur == 0)
4554edf8e2afSMika Westerberg         return 0;
4555edf8e2afSMika Westerberg 
455668af19adSDaniel P. Berrangé     corefile = core_dump_filename(ts);
4557edf8e2afSMika Westerberg 
4558edf8e2afSMika Westerberg     if ((fd = open(corefile, O_WRONLY | O_CREAT,
4559edf8e2afSMika Westerberg                    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
4560edf8e2afSMika Westerberg         return (-errno);
4561edf8e2afSMika Westerberg 
4562edf8e2afSMika Westerberg     /*
4563edf8e2afSMika Westerberg      * Walk through target process memory mappings and
4564edf8e2afSMika Westerberg      * set up structure containing this information.  After
4565edf8e2afSMika Westerberg      * this point vma_xxx functions can be used.
4566edf8e2afSMika Westerberg      */
4567edf8e2afSMika Westerberg     if ((mm = vma_init()) == NULL)
4568edf8e2afSMika Westerberg         goto out;
4569edf8e2afSMika Westerberg 
4570edf8e2afSMika Westerberg     walk_memory_regions(mm, vma_walker);
4571edf8e2afSMika Westerberg     segs = vma_get_mapping_count(mm);
4572edf8e2afSMika Westerberg 
4573edf8e2afSMika Westerberg     /*
4574edf8e2afSMika Westerberg      * Construct valid coredump ELF header.  We also
4575edf8e2afSMika Westerberg      * add one more segment for notes.
4576edf8e2afSMika Westerberg      */
4577edf8e2afSMika Westerberg     fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
4578edf8e2afSMika Westerberg     if (dump_write(fd, &elf, sizeof (elf)) != 0)
4579edf8e2afSMika Westerberg         goto out;
4580edf8e2afSMika Westerberg 
4581b6af0975SDaniel P. Berrange     /* fill in the in-memory version of notes */
4582edf8e2afSMika Westerberg     if (fill_note_info(&info, signr, env) < 0)
4583edf8e2afSMika Westerberg         goto out;
4584edf8e2afSMika Westerberg 
4585edf8e2afSMika Westerberg     offset += sizeof (elf);                             /* elf header */
4586edf8e2afSMika Westerberg     offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
4587edf8e2afSMika Westerberg 
4588edf8e2afSMika Westerberg     /* write out notes program header */
4589edf8e2afSMika Westerberg     fill_elf_note_phdr(&phdr, info.notes_size, offset);
4590edf8e2afSMika Westerberg 
4591edf8e2afSMika Westerberg     offset += info.notes_size;
4592edf8e2afSMika Westerberg     if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
4593edf8e2afSMika Westerberg         goto out;
4594edf8e2afSMika Westerberg 
4595edf8e2afSMika Westerberg     /*
4596edf8e2afSMika Westerberg      * ELF specification wants data to start at page boundary so
4597edf8e2afSMika Westerberg      * we align it here.
4598edf8e2afSMika Westerberg      */
459980f5ce75SLaurent Vivier     data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
4600edf8e2afSMika Westerberg 
4601edf8e2afSMika Westerberg     /*
4602edf8e2afSMika Westerberg      * Write program headers for memory regions mapped in
4603edf8e2afSMika Westerberg      * the target process.
4604edf8e2afSMika Westerberg      */
4605edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4606edf8e2afSMika Westerberg         (void) memset(&phdr, 0, sizeof (phdr));
4607edf8e2afSMika Westerberg 
4608edf8e2afSMika Westerberg         phdr.p_type = PT_LOAD;
4609edf8e2afSMika Westerberg         phdr.p_offset = offset;
4610edf8e2afSMika Westerberg         phdr.p_vaddr = vma->vma_start;
4611edf8e2afSMika Westerberg         phdr.p_paddr = 0;
4612edf8e2afSMika Westerberg         phdr.p_filesz = vma_dump_size(vma);
4613edf8e2afSMika Westerberg         offset += phdr.p_filesz;
4614edf8e2afSMika Westerberg         phdr.p_memsz = vma->vma_end - vma->vma_start;
4615edf8e2afSMika Westerberg         phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
4616edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_WRITE)
4617edf8e2afSMika Westerberg             phdr.p_flags |= PF_W;
4618edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_EXEC)
4619edf8e2afSMika Westerberg             phdr.p_flags |= PF_X;
4620edf8e2afSMika Westerberg         phdr.p_align = ELF_EXEC_PAGESIZE;
4621edf8e2afSMika Westerberg 
462280f5ce75SLaurent Vivier         bswap_phdr(&phdr, 1);
4623772034b6SPeter Maydell         if (dump_write(fd, &phdr, sizeof(phdr)) != 0) {
4624772034b6SPeter Maydell             goto out;
4625772034b6SPeter Maydell         }
4626edf8e2afSMika Westerberg     }
4627edf8e2afSMika Westerberg 
4628edf8e2afSMika Westerberg     /*
4629edf8e2afSMika Westerberg      * Next we write notes just after program headers.  No
4630edf8e2afSMika Westerberg      * alignment needed here.
4631edf8e2afSMika Westerberg      */
4632edf8e2afSMika Westerberg     if (write_note_info(&info, fd) < 0)
4633edf8e2afSMika Westerberg         goto out;
4634edf8e2afSMika Westerberg 
4635edf8e2afSMika Westerberg     /* align data to page boundary */
4636edf8e2afSMika Westerberg     if (lseek(fd, data_offset, SEEK_SET) != data_offset)
4637edf8e2afSMika Westerberg         goto out;
4638edf8e2afSMika Westerberg 
4639edf8e2afSMika Westerberg     /*
4640edf8e2afSMika Westerberg      * Finally we can dump process memory into corefile as well.
4641edf8e2afSMika Westerberg      */
4642edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4643edf8e2afSMika Westerberg         abi_ulong addr;
4644edf8e2afSMika Westerberg         abi_ulong end;
4645edf8e2afSMika Westerberg 
4646edf8e2afSMika Westerberg         end = vma->vma_start + vma_dump_size(vma);
4647edf8e2afSMika Westerberg 
4648edf8e2afSMika Westerberg         for (addr = vma->vma_start; addr < end;
4649edf8e2afSMika Westerberg              addr += TARGET_PAGE_SIZE) {
4650edf8e2afSMika Westerberg             char page[TARGET_PAGE_SIZE];
4651edf8e2afSMika Westerberg             int error;
4652edf8e2afSMika Westerberg 
4653edf8e2afSMika Westerberg             /*
4654edf8e2afSMika Westerberg              *  Read in page from target process memory and
4655edf8e2afSMika Westerberg              *  write it to coredump file.
4656edf8e2afSMika Westerberg              */
4657edf8e2afSMika Westerberg             error = copy_from_user(page, addr, sizeof (page));
4658edf8e2afSMika Westerberg             if (error != 0) {
465949995e17SAurelien Jarno                 (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
4660edf8e2afSMika Westerberg                                addr);
4661edf8e2afSMika Westerberg                 errno = -error;
4662edf8e2afSMika Westerberg                 goto out;
4663edf8e2afSMika Westerberg             }
4664edf8e2afSMika Westerberg             if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
4665edf8e2afSMika Westerberg                 goto out;
4666edf8e2afSMika Westerberg         }
4667edf8e2afSMika Westerberg     }
4668edf8e2afSMika Westerberg 
4669edf8e2afSMika Westerberg  out:
4670edf8e2afSMika Westerberg     free_note_info(&info);
4671edf8e2afSMika Westerberg     if (mm != NULL)
4672edf8e2afSMika Westerberg         vma_delete(mm);
4673edf8e2afSMika Westerberg     (void) close(fd);
4674edf8e2afSMika Westerberg 
4675edf8e2afSMika Westerberg     if (errno != 0)
4676edf8e2afSMika Westerberg         return (-errno);
4677edf8e2afSMika Westerberg     return (0);
4678edf8e2afSMika Westerberg }
4679edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
4680edf8e2afSMika Westerberg 
4681e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
4682e5fe0c52Spbrook {
4683e5fe0c52Spbrook     init_thread(regs, infop);
4684e5fe0c52Spbrook }
4685