xref: /qemu/linux-user/elfload.c (revision 0c441aeb39ce77cf0c68c93f94f1e64addaefaff)
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_START_MMAP 0x2aaaaab000ULL
14784409ddbSj_mayer 
14884409ddbSj_mayer #define ELF_CLASS      ELFCLASS64
14984409ddbSj_mayer #define ELF_ARCH       EM_X86_64
15084409ddbSj_mayer 
1519263ba84SRichard Henderson #define ELF_PLATFORM   "x86_64"
1529263ba84SRichard Henderson 
15384409ddbSj_mayer static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
15484409ddbSj_mayer {
15584409ddbSj_mayer     regs->rax = 0;
15684409ddbSj_mayer     regs->rsp = infop->start_stack;
15784409ddbSj_mayer     regs->rip = infop->entry;
15884409ddbSj_mayer }
15984409ddbSj_mayer 
1609edc5d79SMika Westerberg #define ELF_NREG    27
161c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
1629edc5d79SMika Westerberg 
1639edc5d79SMika Westerberg /*
1649edc5d79SMika Westerberg  * Note that ELF_NREG should be 29 as there should be place for
1659edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
1669edc5d79SMika Westerberg  * those.
1679edc5d79SMika Westerberg  *
1689edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
1699edc5d79SMika Westerberg  */
17005390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
1719edc5d79SMika Westerberg {
172030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[15]);
173030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[14]);
174030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[13]);
175030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[12]);
176030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EBP]);
177030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBX]);
178030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[11]);
179030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->regs[10]);
180030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->regs[9]);
181030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->regs[8]);
182030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->regs[R_EAX]);
183030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_ECX]);
184030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->regs[R_EDX]);
185030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->regs[R_ESI]);
186030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->regs[R_EDI]);
187030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_EAX]); /* XXX */
188030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->eip);
189030912e0SIlya Leoshkevich     (*regs)[17] = tswapreg(env->segs[R_CS].selector & 0xffff);
190030912e0SIlya Leoshkevich     (*regs)[18] = tswapreg(env->eflags);
191030912e0SIlya Leoshkevich     (*regs)[19] = tswapreg(env->regs[R_ESP]);
192030912e0SIlya Leoshkevich     (*regs)[20] = tswapreg(env->segs[R_SS].selector & 0xffff);
193030912e0SIlya Leoshkevich     (*regs)[21] = tswapreg(env->segs[R_FS].selector & 0xffff);
194030912e0SIlya Leoshkevich     (*regs)[22] = tswapreg(env->segs[R_GS].selector & 0xffff);
195030912e0SIlya Leoshkevich     (*regs)[23] = tswapreg(env->segs[R_DS].selector & 0xffff);
196030912e0SIlya Leoshkevich     (*regs)[24] = tswapreg(env->segs[R_ES].selector & 0xffff);
197030912e0SIlya Leoshkevich     (*regs)[25] = tswapreg(env->segs[R_FS].selector & 0xffff);
198030912e0SIlya Leoshkevich     (*regs)[26] = tswapreg(env->segs[R_GS].selector & 0xffff);
1999edc5d79SMika Westerberg }
2009edc5d79SMika Westerberg 
201d461b73eSRichard Henderson #if ULONG_MAX > UINT32_MAX
202d461b73eSRichard Henderson #define INIT_GUEST_COMMPAGE
203d461b73eSRichard Henderson static bool init_guest_commpage(void)
204d461b73eSRichard Henderson {
205d461b73eSRichard Henderson     /*
206d461b73eSRichard Henderson      * The vsyscall page is at a high negative address aka kernel space,
207d461b73eSRichard Henderson      * which means that we cannot actually allocate it with target_mmap.
208d461b73eSRichard Henderson      * We still should be able to use page_set_flags, unless the user
209d461b73eSRichard Henderson      * has specified -R reserved_va, which would trigger an assert().
210d461b73eSRichard Henderson      */
211d461b73eSRichard Henderson     if (reserved_va != 0 &&
21295059f9cSRichard Henderson         TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE - 1 > reserved_va) {
213d461b73eSRichard Henderson         error_report("Cannot allocate vsyscall page");
214d461b73eSRichard Henderson         exit(EXIT_FAILURE);
215d461b73eSRichard Henderson     }
216d461b73eSRichard Henderson     page_set_flags(TARGET_VSYSCALL_PAGE,
21749840a4aSRichard Henderson                    TARGET_VSYSCALL_PAGE | ~TARGET_PAGE_MASK,
218d461b73eSRichard Henderson                    PAGE_EXEC | PAGE_VALID);
219d461b73eSRichard Henderson     return true;
220d461b73eSRichard Henderson }
221d461b73eSRichard Henderson #endif
22284409ddbSj_mayer #else
22384409ddbSj_mayer 
22430ac07d4Sbellard #define ELF_START_MMAP 0x80000000
22530ac07d4Sbellard 
22630ac07d4Sbellard /*
22730ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
22830ac07d4Sbellard  */
22930ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
23030ac07d4Sbellard 
23130ac07d4Sbellard /*
23230ac07d4Sbellard  * These are used to set parameters in the core dumps.
23330ac07d4Sbellard  */
23430ac07d4Sbellard #define ELF_CLASS       ELFCLASS32
23530ac07d4Sbellard #define ELF_ARCH        EM_386
23630ac07d4Sbellard 
2379263ba84SRichard Henderson #define ELF_PLATFORM get_elf_platform()
238872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
2399263ba84SRichard Henderson 
2409263ba84SRichard Henderson static const char *get_elf_platform(void)
2419263ba84SRichard Henderson {
2429263ba84SRichard Henderson     static char elf_platform[] = "i386";
2439263ba84SRichard Henderson     int family = object_property_get_int(OBJECT(thread_cpu), "family", NULL);
2449263ba84SRichard Henderson     if (family > 6) {
2459263ba84SRichard Henderson         family = 6;
2469263ba84SRichard Henderson     }
2479263ba84SRichard Henderson     if (family >= 3) {
2489263ba84SRichard Henderson         elf_platform[1] = '0' + family;
2499263ba84SRichard Henderson     }
2509263ba84SRichard Henderson     return elf_platform;
2519263ba84SRichard Henderson }
2529263ba84SRichard Henderson 
253d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
254d97ef72eSRichard Henderson                                struct image_info *infop)
255e5fe0c52Spbrook {
256e5fe0c52Spbrook     regs->esp = infop->start_stack;
257e5fe0c52Spbrook     regs->eip = infop->entry;
258e5fe0c52Spbrook 
25930ac07d4Sbellard     /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
26030ac07d4Sbellard        starts %edx contains a pointer to a function which might be
26130ac07d4Sbellard        registered using `atexit'.  This provides a mean for the
26230ac07d4Sbellard        dynamic linker to call DT_FINI functions for shared libraries
26330ac07d4Sbellard        that have been loaded before the code runs.
26430ac07d4Sbellard 
26530ac07d4Sbellard        A value of 0 tells we have no such handler.  */
266e5fe0c52Spbrook     regs->edx = 0;
267b346ff46Sbellard }
2689edc5d79SMika Westerberg 
2699edc5d79SMika Westerberg #define ELF_NREG    17
270c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
2719edc5d79SMika Westerberg 
2729edc5d79SMika Westerberg /*
2739edc5d79SMika Westerberg  * Note that ELF_NREG should be 19 as there should be place for
2749edc5d79SMika Westerberg  * TRAPNO and ERR "registers" as well but linux doesn't dump
2759edc5d79SMika Westerberg  * those.
2769edc5d79SMika Westerberg  *
2779edc5d79SMika Westerberg  * See linux kernel: arch/x86/include/asm/elf.h
2789edc5d79SMika Westerberg  */
27905390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *env)
2809edc5d79SMika Westerberg {
281030912e0SIlya Leoshkevich     (*regs)[0] = tswapreg(env->regs[R_EBX]);
282030912e0SIlya Leoshkevich     (*regs)[1] = tswapreg(env->regs[R_ECX]);
283030912e0SIlya Leoshkevich     (*regs)[2] = tswapreg(env->regs[R_EDX]);
284030912e0SIlya Leoshkevich     (*regs)[3] = tswapreg(env->regs[R_ESI]);
285030912e0SIlya Leoshkevich     (*regs)[4] = tswapreg(env->regs[R_EDI]);
286030912e0SIlya Leoshkevich     (*regs)[5] = tswapreg(env->regs[R_EBP]);
287030912e0SIlya Leoshkevich     (*regs)[6] = tswapreg(env->regs[R_EAX]);
288030912e0SIlya Leoshkevich     (*regs)[7] = tswapreg(env->segs[R_DS].selector & 0xffff);
289030912e0SIlya Leoshkevich     (*regs)[8] = tswapreg(env->segs[R_ES].selector & 0xffff);
290030912e0SIlya Leoshkevich     (*regs)[9] = tswapreg(env->segs[R_FS].selector & 0xffff);
291030912e0SIlya Leoshkevich     (*regs)[10] = tswapreg(env->segs[R_GS].selector & 0xffff);
292030912e0SIlya Leoshkevich     (*regs)[11] = tswapreg(env->regs[R_EAX]); /* XXX */
293030912e0SIlya Leoshkevich     (*regs)[12] = tswapreg(env->eip);
294030912e0SIlya Leoshkevich     (*regs)[13] = tswapreg(env->segs[R_CS].selector & 0xffff);
295030912e0SIlya Leoshkevich     (*regs)[14] = tswapreg(env->eflags);
296030912e0SIlya Leoshkevich     (*regs)[15] = tswapreg(env->regs[R_ESP]);
297030912e0SIlya Leoshkevich     (*regs)[16] = tswapreg(env->segs[R_SS].selector & 0xffff);
2989edc5d79SMika Westerberg }
29984409ddbSj_mayer #endif
300b346ff46Sbellard 
3019edc5d79SMika Westerberg #define USE_ELF_CORE_DUMP
302b346ff46Sbellard #define ELF_EXEC_PAGESIZE       4096
303b346ff46Sbellard 
304b346ff46Sbellard #endif
305b346ff46Sbellard 
306b346ff46Sbellard #ifdef TARGET_ARM
307b346ff46Sbellard 
30824e76ff0SPeter Maydell #ifndef TARGET_AARCH64
30924e76ff0SPeter Maydell /* 32 bit ARM definitions */
31024e76ff0SPeter Maydell 
311b346ff46Sbellard #define ELF_START_MMAP 0x80000000
312b346ff46Sbellard 
313b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_ARM
314b346ff46Sbellard #define ELF_CLASS       ELFCLASS32
315872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
316b346ff46Sbellard 
317d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
318d97ef72eSRichard Henderson                                struct image_info *infop)
319b346ff46Sbellard {
320992f48a0Sblueswir1     abi_long stack = infop->start_stack;
321b346ff46Sbellard     memset(regs, 0, sizeof(*regs));
32299033caeSAlexander Graf 
323167e4cdcSPeter Maydell     regs->uregs[16] = ARM_CPU_MODE_USR;
324167e4cdcSPeter Maydell     if (infop->entry & 1) {
325167e4cdcSPeter Maydell         regs->uregs[16] |= CPSR_T;
326167e4cdcSPeter Maydell     }
327167e4cdcSPeter Maydell     regs->uregs[15] = infop->entry & 0xfffffffe;
328167e4cdcSPeter Maydell     regs->uregs[13] = infop->start_stack;
3292f619698Sbellard     /* FIXME - what to for failure of get_user()? */
330167e4cdcSPeter Maydell     get_user_ual(regs->uregs[2], stack + 8); /* envp */
331167e4cdcSPeter Maydell     get_user_ual(regs->uregs[1], stack + 4); /* envp */
332a1516e92Sbellard     /* XXX: it seems that r0 is zeroed after ! */
333167e4cdcSPeter Maydell     regs->uregs[0] = 0;
334e5fe0c52Spbrook     /* For uClinux PIC binaries.  */
335863cf0b7Sj_mayer     /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
336167e4cdcSPeter Maydell     regs->uregs[10] = infop->start_data;
3373cb10cfaSChristophe Lyon 
3383cb10cfaSChristophe Lyon     /* Support ARM FDPIC.  */
3393cb10cfaSChristophe Lyon     if (info_is_fdpic(infop)) {
3403cb10cfaSChristophe Lyon         /* As described in the ABI document, r7 points to the loadmap info
3413cb10cfaSChristophe Lyon          * prepared by the kernel. If an interpreter is needed, r8 points
3423cb10cfaSChristophe Lyon          * to the interpreter loadmap and r9 points to the interpreter
3433cb10cfaSChristophe Lyon          * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
3443cb10cfaSChristophe Lyon          * r9 points to the main program PT_DYNAMIC info.
3453cb10cfaSChristophe Lyon          */
3463cb10cfaSChristophe Lyon         regs->uregs[7] = infop->loadmap_addr;
3473cb10cfaSChristophe Lyon         if (infop->interpreter_loadmap_addr) {
3483cb10cfaSChristophe Lyon             /* Executable is dynamically loaded.  */
3493cb10cfaSChristophe Lyon             regs->uregs[8] = infop->interpreter_loadmap_addr;
3503cb10cfaSChristophe Lyon             regs->uregs[9] = infop->interpreter_pt_dynamic_addr;
3513cb10cfaSChristophe Lyon         } else {
3523cb10cfaSChristophe Lyon             regs->uregs[8] = 0;
3533cb10cfaSChristophe Lyon             regs->uregs[9] = infop->pt_dynamic_addr;
3543cb10cfaSChristophe Lyon         }
3553cb10cfaSChristophe Lyon     }
356b346ff46Sbellard }
357b346ff46Sbellard 
358edf8e2afSMika Westerberg #define ELF_NREG    18
359c227f099SAnthony Liguori typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
360edf8e2afSMika Westerberg 
36105390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUARMState *env)
362edf8e2afSMika Westerberg {
36386cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->regs[0]);
36486cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->regs[1]);
36586cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->regs[2]);
36686cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->regs[3]);
36786cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->regs[4]);
36886cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->regs[5]);
36986cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->regs[6]);
37086cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->regs[7]);
37186cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->regs[8]);
37286cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->regs[9]);
37386cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->regs[10]);
37486cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->regs[11]);
37586cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->regs[12]);
37686cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->regs[13]);
37786cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->regs[14]);
37886cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->regs[15]);
379edf8e2afSMika Westerberg 
38086cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(cpsr_read((CPUARMState *)env));
38186cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->regs[0]); /* XXX */
382edf8e2afSMika Westerberg }
383edf8e2afSMika Westerberg 
38430ac07d4Sbellard #define USE_ELF_CORE_DUMP
38530ac07d4Sbellard #define ELF_EXEC_PAGESIZE       4096
38630ac07d4Sbellard 
387afce2927Sbellard enum
388afce2927Sbellard {
389afce2927Sbellard     ARM_HWCAP_ARM_SWP       = 1 << 0,
390afce2927Sbellard     ARM_HWCAP_ARM_HALF      = 1 << 1,
391afce2927Sbellard     ARM_HWCAP_ARM_THUMB     = 1 << 2,
392afce2927Sbellard     ARM_HWCAP_ARM_26BIT     = 1 << 3,
393afce2927Sbellard     ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
394afce2927Sbellard     ARM_HWCAP_ARM_FPA       = 1 << 5,
395afce2927Sbellard     ARM_HWCAP_ARM_VFP       = 1 << 6,
396afce2927Sbellard     ARM_HWCAP_ARM_EDSP      = 1 << 7,
397cf6de34aSRiku Voipio     ARM_HWCAP_ARM_JAVA      = 1 << 8,
398cf6de34aSRiku Voipio     ARM_HWCAP_ARM_IWMMXT    = 1 << 9,
39943ce393eSPeter Maydell     ARM_HWCAP_ARM_CRUNCH    = 1 << 10,
40043ce393eSPeter Maydell     ARM_HWCAP_ARM_THUMBEE   = 1 << 11,
40143ce393eSPeter Maydell     ARM_HWCAP_ARM_NEON      = 1 << 12,
40243ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3     = 1 << 13,
40343ce393eSPeter Maydell     ARM_HWCAP_ARM_VFPv3D16  = 1 << 14,
40424682654SPeter Maydell     ARM_HWCAP_ARM_TLS       = 1 << 15,
40524682654SPeter Maydell     ARM_HWCAP_ARM_VFPv4     = 1 << 16,
40624682654SPeter Maydell     ARM_HWCAP_ARM_IDIVA     = 1 << 17,
40724682654SPeter Maydell     ARM_HWCAP_ARM_IDIVT     = 1 << 18,
40824682654SPeter Maydell     ARM_HWCAP_ARM_VFPD32    = 1 << 19,
40924682654SPeter Maydell     ARM_HWCAP_ARM_LPAE      = 1 << 20,
41024682654SPeter Maydell     ARM_HWCAP_ARM_EVTSTRM   = 1 << 21,
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,
419ad6919dcSPeter Maydell };
420ad6919dcSPeter Maydell 
4216b1275ffSPeter Maydell /* The commpage only exists for 32 bit kernels */
4226b1275ffSPeter Maydell 
42366346fafSRichard Henderson #define HI_COMMPAGE (intptr_t)0xffff0f00u
424ee947430SAlex Bennée 
425ee947430SAlex Bennée static bool init_guest_commpage(void)
42697cc7560SDr. David Alan Gilbert {
427d713cf4dSPhilippe Mathieu-Daudé     ARMCPU *cpu = ARM_CPU(thread_cpu);
428d713cf4dSPhilippe Mathieu-Daudé     abi_ptr commpage;
429d713cf4dSPhilippe Mathieu-Daudé     void *want;
430d713cf4dSPhilippe Mathieu-Daudé     void *addr;
431d713cf4dSPhilippe Mathieu-Daudé 
432d713cf4dSPhilippe Mathieu-Daudé     /*
433d713cf4dSPhilippe Mathieu-Daudé      * M-profile allocates maximum of 2GB address space, so can never
434d713cf4dSPhilippe Mathieu-Daudé      * allocate the commpage.  Skip it.
435d713cf4dSPhilippe Mathieu-Daudé      */
436d713cf4dSPhilippe Mathieu-Daudé     if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
437d713cf4dSPhilippe Mathieu-Daudé         return true;
438d713cf4dSPhilippe Mathieu-Daudé     }
439d713cf4dSPhilippe Mathieu-Daudé 
440d713cf4dSPhilippe Mathieu-Daudé     commpage = HI_COMMPAGE & -qemu_host_page_size;
441d713cf4dSPhilippe Mathieu-Daudé     want = g2h_untagged(commpage);
442d713cf4dSPhilippe Mathieu-Daudé     addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
4435c3e87f3SAlex Bennée                 MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
44497cc7560SDr. David Alan Gilbert 
4456cda41daSRichard Henderson     if (addr == MAP_FAILED) {
446ee947430SAlex Bennée         perror("Allocating guest commpage");
447ee947430SAlex Bennée         exit(EXIT_FAILURE);
448ee947430SAlex Bennée     }
449ee947430SAlex Bennée     if (addr != want) {
450ee947430SAlex Bennée         return false;
451806d1021SMeador Inge     }
452806d1021SMeador Inge 
453ee947430SAlex Bennée     /* Set kernel helper versions; rest of page is 0.  */
4546cda41daSRichard Henderson     __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu));
45597cc7560SDr. David Alan Gilbert 
4566cda41daSRichard Henderson     if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
45797cc7560SDr. David Alan Gilbert         perror("Protecting guest commpage");
458ee947430SAlex Bennée         exit(EXIT_FAILURE);
45997cc7560SDr. David Alan Gilbert     }
4606cda41daSRichard Henderson 
4616cda41daSRichard Henderson     page_set_flags(commpage, commpage | ~qemu_host_page_mask,
4626cda41daSRichard Henderson                    PAGE_READ | PAGE_EXEC | PAGE_VALID);
463ee947430SAlex Bennée     return true;
46497cc7560SDr. David Alan Gilbert }
465adf050b1SBenoit Canet 
466adf050b1SBenoit Canet #define ELF_HWCAP get_elf_hwcap()
467ad6919dcSPeter Maydell #define ELF_HWCAP2 get_elf_hwcap2()
468adf050b1SBenoit Canet 
469adf050b1SBenoit Canet static uint32_t get_elf_hwcap(void)
470adf050b1SBenoit Canet {
471a2247f8eSAndreas Färber     ARMCPU *cpu = ARM_CPU(thread_cpu);
472adf050b1SBenoit Canet     uint32_t hwcaps = 0;
473adf050b1SBenoit Canet 
474adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_SWP;
475adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_HALF;
476adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_THUMB;
477adf050b1SBenoit Canet     hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
478adf050b1SBenoit Canet 
479adf050b1SBenoit Canet     /* probe for the extra features */
480adf050b1SBenoit Canet #define GET_FEATURE(feat, hwcap) \
481a2247f8eSAndreas Färber     do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
482962fcbf2SRichard Henderson 
483962fcbf2SRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
484962fcbf2SRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
485962fcbf2SRichard Henderson 
48624682654SPeter Maydell     /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
48724682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
488adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
489adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
490adf050b1SBenoit Canet     GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
49124682654SPeter Maydell     GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
492bfa8a370SRichard Henderson     GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
493873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA);
494873b73c0SPeter Maydell     GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT);
495bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP);
496bfa8a370SRichard Henderson 
497bfa8a370SRichard Henderson     if (cpu_isar_feature(aa32_fpsp_v3, cpu) ||
498bfa8a370SRichard Henderson         cpu_isar_feature(aa32_fpdp_v3, cpu)) {
499bfa8a370SRichard Henderson         hwcaps |= ARM_HWCAP_ARM_VFPv3;
500bfa8a370SRichard Henderson         if (cpu_isar_feature(aa32_simd_r32, cpu)) {
501bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPD32;
502bfa8a370SRichard Henderson         } else {
503bfa8a370SRichard Henderson             hwcaps |= ARM_HWCAP_ARM_VFPv3D16;
504bfa8a370SRichard Henderson         }
505bfa8a370SRichard Henderson     }
506bfa8a370SRichard Henderson     GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4);
507adf050b1SBenoit Canet 
508adf050b1SBenoit Canet     return hwcaps;
509adf050b1SBenoit Canet }
510afce2927Sbellard 
511ad6919dcSPeter Maydell static uint32_t get_elf_hwcap2(void)
512ad6919dcSPeter Maydell {
513ad6919dcSPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
514ad6919dcSPeter Maydell     uint32_t hwcaps = 0;
515ad6919dcSPeter Maydell 
516962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_aes, ARM_HWCAP2_ARM_AES);
517962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_pmull, ARM_HWCAP2_ARM_PMULL);
518962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha1, ARM_HWCAP2_ARM_SHA1);
519962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_sha2, ARM_HWCAP2_ARM_SHA2);
520962fcbf2SRichard Henderson     GET_FEATURE_ID(aa32_crc32, ARM_HWCAP2_ARM_CRC32);
521ad6919dcSPeter Maydell     return hwcaps;
522ad6919dcSPeter Maydell }
523ad6919dcSPeter Maydell 
524ad6919dcSPeter Maydell #undef GET_FEATURE
525962fcbf2SRichard Henderson #undef GET_FEATURE_ID
526ad6919dcSPeter Maydell 
52713ec4ec3SRichard Henderson #define ELF_PLATFORM get_elf_platform()
52813ec4ec3SRichard Henderson 
52913ec4ec3SRichard Henderson static const char *get_elf_platform(void)
53013ec4ec3SRichard Henderson {
53113ec4ec3SRichard Henderson     CPUARMState *env = thread_cpu->env_ptr;
53213ec4ec3SRichard Henderson 
533ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
53413ec4ec3SRichard Henderson # define END  "b"
53513ec4ec3SRichard Henderson #else
53613ec4ec3SRichard Henderson # define END  "l"
53713ec4ec3SRichard Henderson #endif
53813ec4ec3SRichard Henderson 
53913ec4ec3SRichard Henderson     if (arm_feature(env, ARM_FEATURE_V8)) {
54013ec4ec3SRichard Henderson         return "v8" END;
54113ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V7)) {
54213ec4ec3SRichard Henderson         if (arm_feature(env, ARM_FEATURE_M)) {
54313ec4ec3SRichard Henderson             return "v7m" END;
54413ec4ec3SRichard Henderson         } else {
54513ec4ec3SRichard Henderson             return "v7" END;
54613ec4ec3SRichard Henderson         }
54713ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V6)) {
54813ec4ec3SRichard Henderson         return "v6" END;
54913ec4ec3SRichard Henderson     } else if (arm_feature(env, ARM_FEATURE_V5)) {
55013ec4ec3SRichard Henderson         return "v5" END;
55113ec4ec3SRichard Henderson     } else {
55213ec4ec3SRichard Henderson         return "v4" END;
55313ec4ec3SRichard Henderson     }
55413ec4ec3SRichard Henderson 
55513ec4ec3SRichard Henderson #undef END
55613ec4ec3SRichard Henderson }
55713ec4ec3SRichard Henderson 
55824e76ff0SPeter Maydell #else
55924e76ff0SPeter Maydell /* 64 bit ARM definitions */
56024e76ff0SPeter Maydell #define ELF_START_MMAP 0x80000000
56124e76ff0SPeter Maydell 
562b597c3f7SPeter Crosthwaite #define ELF_ARCH        EM_AARCH64
56324e76ff0SPeter Maydell #define ELF_CLASS       ELFCLASS64
564ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
565e20e3ec9SRichard Henderson # define ELF_PLATFORM    "aarch64_be"
566e20e3ec9SRichard Henderson #else
56724e76ff0SPeter Maydell # define ELF_PLATFORM    "aarch64"
568e20e3ec9SRichard Henderson #endif
56924e76ff0SPeter Maydell 
57024e76ff0SPeter Maydell static inline void init_thread(struct target_pt_regs *regs,
57124e76ff0SPeter Maydell                                struct image_info *infop)
57224e76ff0SPeter Maydell {
57324e76ff0SPeter Maydell     abi_long stack = infop->start_stack;
57424e76ff0SPeter Maydell     memset(regs, 0, sizeof(*regs));
57524e76ff0SPeter Maydell 
57624e76ff0SPeter Maydell     regs->pc = infop->entry & ~0x3ULL;
57724e76ff0SPeter Maydell     regs->sp = stack;
57824e76ff0SPeter Maydell }
57924e76ff0SPeter Maydell 
58024e76ff0SPeter Maydell #define ELF_NREG    34
58124e76ff0SPeter Maydell typedef target_elf_greg_t  target_elf_gregset_t[ELF_NREG];
58224e76ff0SPeter Maydell 
58324e76ff0SPeter Maydell static void elf_core_copy_regs(target_elf_gregset_t *regs,
58424e76ff0SPeter Maydell                                const CPUARMState *env)
58524e76ff0SPeter Maydell {
58624e76ff0SPeter Maydell     int i;
58724e76ff0SPeter Maydell 
58824e76ff0SPeter Maydell     for (i = 0; i < 32; i++) {
58924e76ff0SPeter Maydell         (*regs)[i] = tswapreg(env->xregs[i]);
59024e76ff0SPeter Maydell     }
59124e76ff0SPeter Maydell     (*regs)[32] = tswapreg(env->pc);
59224e76ff0SPeter Maydell     (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env));
59324e76ff0SPeter Maydell }
59424e76ff0SPeter Maydell 
59524e76ff0SPeter Maydell #define USE_ELF_CORE_DUMP
59624e76ff0SPeter Maydell #define ELF_EXEC_PAGESIZE       4096
59724e76ff0SPeter Maydell 
59824e76ff0SPeter Maydell enum {
59924e76ff0SPeter Maydell     ARM_HWCAP_A64_FP            = 1 << 0,
60024e76ff0SPeter Maydell     ARM_HWCAP_A64_ASIMD         = 1 << 1,
60124e76ff0SPeter Maydell     ARM_HWCAP_A64_EVTSTRM       = 1 << 2,
60224e76ff0SPeter Maydell     ARM_HWCAP_A64_AES           = 1 << 3,
60324e76ff0SPeter Maydell     ARM_HWCAP_A64_PMULL         = 1 << 4,
60424e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA1          = 1 << 5,
60524e76ff0SPeter Maydell     ARM_HWCAP_A64_SHA2          = 1 << 6,
60624e76ff0SPeter Maydell     ARM_HWCAP_A64_CRC32         = 1 << 7,
607955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ATOMICS       = 1 << 8,
608955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FPHP          = 1 << 9,
609955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDHP       = 1 << 10,
610955f56d4SArd Biesheuvel     ARM_HWCAP_A64_CPUID         = 1 << 11,
611955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDRDM      = 1 << 12,
612955f56d4SArd Biesheuvel     ARM_HWCAP_A64_JSCVT         = 1 << 13,
613955f56d4SArd Biesheuvel     ARM_HWCAP_A64_FCMA          = 1 << 14,
614955f56d4SArd Biesheuvel     ARM_HWCAP_A64_LRCPC         = 1 << 15,
615955f56d4SArd Biesheuvel     ARM_HWCAP_A64_DCPOP         = 1 << 16,
616955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA3          = 1 << 17,
617955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM3           = 1 << 18,
618955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SM4           = 1 << 19,
619955f56d4SArd Biesheuvel     ARM_HWCAP_A64_ASIMDDP       = 1 << 20,
620955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SHA512        = 1 << 21,
621955f56d4SArd Biesheuvel     ARM_HWCAP_A64_SVE           = 1 << 22,
6220083a1faSRichard Henderson     ARM_HWCAP_A64_ASIMDFHM      = 1 << 23,
6230083a1faSRichard Henderson     ARM_HWCAP_A64_DIT           = 1 << 24,
6240083a1faSRichard Henderson     ARM_HWCAP_A64_USCAT         = 1 << 25,
6250083a1faSRichard Henderson     ARM_HWCAP_A64_ILRCPC        = 1 << 26,
6260083a1faSRichard Henderson     ARM_HWCAP_A64_FLAGM         = 1 << 27,
6270083a1faSRichard Henderson     ARM_HWCAP_A64_SSBS          = 1 << 28,
6280083a1faSRichard Henderson     ARM_HWCAP_A64_SB            = 1 << 29,
6290083a1faSRichard Henderson     ARM_HWCAP_A64_PACA          = 1 << 30,
6300083a1faSRichard Henderson     ARM_HWCAP_A64_PACG          = 1UL << 31,
6312041df4aSRichard Henderson 
6322041df4aSRichard Henderson     ARM_HWCAP2_A64_DCPODP       = 1 << 0,
6332041df4aSRichard Henderson     ARM_HWCAP2_A64_SVE2         = 1 << 1,
6342041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEAES       = 1 << 2,
6352041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEPMULL     = 1 << 3,
6362041df4aSRichard Henderson     ARM_HWCAP2_A64_SVEBITPERM   = 1 << 4,
6372041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESHA3      = 1 << 5,
6382041df4aSRichard Henderson     ARM_HWCAP2_A64_SVESM4       = 1 << 6,
6392041df4aSRichard Henderson     ARM_HWCAP2_A64_FLAGM2       = 1 << 7,
6402041df4aSRichard Henderson     ARM_HWCAP2_A64_FRINT        = 1 << 8,
64168948d18SRichard Henderson     ARM_HWCAP2_A64_SVEI8MM      = 1 << 9,
64268948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF32MM     = 1 << 10,
64368948d18SRichard Henderson     ARM_HWCAP2_A64_SVEF64MM     = 1 << 11,
64468948d18SRichard Henderson     ARM_HWCAP2_A64_SVEBF16      = 1 << 12,
64568948d18SRichard Henderson     ARM_HWCAP2_A64_I8MM         = 1 << 13,
64668948d18SRichard Henderson     ARM_HWCAP2_A64_BF16         = 1 << 14,
64768948d18SRichard Henderson     ARM_HWCAP2_A64_DGH          = 1 << 15,
64868948d18SRichard Henderson     ARM_HWCAP2_A64_RNG          = 1 << 16,
64968948d18SRichard Henderson     ARM_HWCAP2_A64_BTI          = 1 << 17,
65068948d18SRichard Henderson     ARM_HWCAP2_A64_MTE          = 1 << 18,
651f9982ceaSRichard Henderson     ARM_HWCAP2_A64_ECV          = 1 << 19,
652f9982ceaSRichard Henderson     ARM_HWCAP2_A64_AFP          = 1 << 20,
653f9982ceaSRichard Henderson     ARM_HWCAP2_A64_RPRES        = 1 << 21,
654f9982ceaSRichard Henderson     ARM_HWCAP2_A64_MTE3         = 1 << 22,
655f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME          = 1 << 23,
656f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I16I64   = 1 << 24,
657f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F64F64   = 1 << 25,
658f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_I8I32    = 1 << 26,
659f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F16F32   = 1 << 27,
660f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_B16F32   = 1 << 28,
661f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_F32F32   = 1 << 29,
662f9982ceaSRichard Henderson     ARM_HWCAP2_A64_SME_FA64     = 1 << 30,
66324e76ff0SPeter Maydell };
66424e76ff0SPeter Maydell 
66524e76ff0SPeter Maydell #define ELF_HWCAP   get_elf_hwcap()
6662041df4aSRichard Henderson #define ELF_HWCAP2  get_elf_hwcap2()
6672041df4aSRichard Henderson 
6682041df4aSRichard Henderson #define GET_FEATURE_ID(feat, hwcap) \
6692041df4aSRichard Henderson     do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
67024e76ff0SPeter Maydell 
67124e76ff0SPeter Maydell static uint32_t get_elf_hwcap(void)
67224e76ff0SPeter Maydell {
67324e76ff0SPeter Maydell     ARMCPU *cpu = ARM_CPU(thread_cpu);
67424e76ff0SPeter Maydell     uint32_t hwcaps = 0;
67524e76ff0SPeter Maydell 
67624e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_FP;
67724e76ff0SPeter Maydell     hwcaps |= ARM_HWCAP_A64_ASIMD;
67837020ff1SAlex Bennée     hwcaps |= ARM_HWCAP_A64_CPUID;
67924e76ff0SPeter Maydell 
68024e76ff0SPeter Maydell     /* probe for the extra features */
681962fcbf2SRichard Henderson 
682962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES);
683962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL);
684962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha1, ARM_HWCAP_A64_SHA1);
685962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha256, ARM_HWCAP_A64_SHA2);
686962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha512, ARM_HWCAP_A64_SHA512);
687962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_crc32, ARM_HWCAP_A64_CRC32);
688962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sha3, ARM_HWCAP_A64_SHA3);
689962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm3, ARM_HWCAP_A64_SM3);
690962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_sm4, ARM_HWCAP_A64_SM4);
6915763190fSRichard Henderson     GET_FEATURE_ID(aa64_fp16, ARM_HWCAP_A64_FPHP | ARM_HWCAP_A64_ASIMDHP);
692962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_atomics, ARM_HWCAP_A64_ATOMICS);
693962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_rdm, ARM_HWCAP_A64_ASIMDRDM);
694962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_dp, ARM_HWCAP_A64_ASIMDDP);
695962fcbf2SRichard Henderson     GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA);
696cd208a1cSRichard Henderson     GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE);
69729d26ab2SRichard Henderson     GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG);
6981c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM);
6991c9af3a9SRichard Henderson     GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
7009888bd1eSRichard Henderson     GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
701b89d9c98SRichard Henderson     GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
7020d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
7032677cf9fSPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
704a1229109SPeter Maydell     GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
705962fcbf2SRichard Henderson 
7062041df4aSRichard Henderson     return hwcaps;
7072041df4aSRichard Henderson }
7082041df4aSRichard Henderson 
7092041df4aSRichard Henderson static uint32_t get_elf_hwcap2(void)
7102041df4aSRichard Henderson {
7112041df4aSRichard Henderson     ARMCPU *cpu = ARM_CPU(thread_cpu);
7122041df4aSRichard Henderson     uint32_t hwcaps = 0;
7132041df4aSRichard Henderson 
7140d57b499SBeata Michalska     GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
715cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2, ARM_HWCAP2_A64_SVE2);
716cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_aes, ARM_HWCAP2_A64_SVEAES);
717cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_pmull128, ARM_HWCAP2_A64_SVEPMULL);
718cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_bitperm, ARM_HWCAP2_A64_SVEBITPERM);
719cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sha3, ARM_HWCAP2_A64_SVESHA3);
720cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve2_sm4, ARM_HWCAP2_A64_SVESM4);
7212041df4aSRichard Henderson     GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
7222041df4aSRichard Henderson     GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
723cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_i8mm, ARM_HWCAP2_A64_SVEI8MM);
724cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f32mm, ARM_HWCAP2_A64_SVEF32MM);
725cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_sve_f64mm, ARM_HWCAP2_A64_SVEF64MM);
7266c47a905SRichard Henderson     GET_FEATURE_ID(aa64_sve_bf16, ARM_HWCAP2_A64_SVEBF16);
727cdc8d8b2SRichard Henderson     GET_FEATURE_ID(aa64_i8mm, ARM_HWCAP2_A64_I8MM);
7286c47a905SRichard Henderson     GET_FEATURE_ID(aa64_bf16, ARM_HWCAP2_A64_BF16);
72968948d18SRichard Henderson     GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG);
73068948d18SRichard Henderson     GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI);
73168948d18SRichard Henderson     GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE);
732f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme, (ARM_HWCAP2_A64_SME |
733f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F32F32 |
734f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_B16F32 |
735f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_F16F32 |
736f9982ceaSRichard Henderson                               ARM_HWCAP2_A64_SME_I8I32));
737f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_f64f64, ARM_HWCAP2_A64_SME_F64F64);
738f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_i16i64, ARM_HWCAP2_A64_SME_I16I64);
739f9982ceaSRichard Henderson     GET_FEATURE_ID(aa64_sme_fa64, ARM_HWCAP2_A64_SME_FA64);
74024e76ff0SPeter Maydell 
74124e76ff0SPeter Maydell     return hwcaps;
74224e76ff0SPeter Maydell }
74324e76ff0SPeter Maydell 
7442041df4aSRichard Henderson #undef GET_FEATURE_ID
7452041df4aSRichard Henderson 
74624e76ff0SPeter Maydell #endif /* not TARGET_AARCH64 */
74724e76ff0SPeter Maydell #endif /* TARGET_ARM */
74830ac07d4Sbellard 
749853d6f7aSbellard #ifdef TARGET_SPARC
750a315a145Sbellard #ifdef TARGET_SPARC64
751853d6f7aSbellard 
752853d6f7aSbellard #define ELF_START_MMAP 0x80000000
753cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
754cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV | HWCAP_SPARC_V9)
755992f48a0Sblueswir1 #ifndef TARGET_ABI32
756cb33da57Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS )
757992f48a0Sblueswir1 #else
758992f48a0Sblueswir1 #define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC )
759992f48a0Sblueswir1 #endif
760853d6f7aSbellard 
761a315a145Sbellard #define ELF_CLASS   ELFCLASS64
7625ef54116Sbellard #define ELF_ARCH    EM_SPARCV9
763a315a145Sbellard #else
764a315a145Sbellard #define ELF_START_MMAP 0x80000000
765cf973e46SArtyom Tarasenko #define ELF_HWCAP  (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
766cf973e46SArtyom Tarasenko                     | HWCAP_SPARC_MULDIV)
767853d6f7aSbellard #define ELF_CLASS   ELFCLASS32
768853d6f7aSbellard #define ELF_ARCH    EM_SPARC
769089a2256SRichard Henderson #endif /* TARGET_SPARC64 */
770853d6f7aSbellard 
771d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
772d97ef72eSRichard Henderson                                struct image_info *infop)
773853d6f7aSbellard {
774089a2256SRichard Henderson     /* Note that target_cpu_copy_regs does not read psr/tstate. */
775f5155289Sbellard     regs->pc = infop->entry;
776f5155289Sbellard     regs->npc = regs->pc + 4;
777f5155289Sbellard     regs->y = 0;
778089a2256SRichard Henderson     regs->u_regs[14] = (infop->start_stack - 16 * sizeof(abi_ulong)
779089a2256SRichard Henderson                         - TARGET_STACK_BIAS);
780853d6f7aSbellard }
781089a2256SRichard Henderson #endif /* TARGET_SPARC */
782853d6f7aSbellard 
78367867308Sbellard #ifdef TARGET_PPC
78467867308Sbellard 
7854ecd4d16SPeter Crosthwaite #define ELF_MACHINE    PPC_ELF_MACHINE
78667867308Sbellard #define ELF_START_MMAP 0x80000000
78767867308Sbellard 
78874154d7eSThomas Huth #if defined(TARGET_PPC64)
78984409ddbSj_mayer 
79084409ddbSj_mayer #define elf_check_arch(x) ( (x) == EM_PPC64 )
79184409ddbSj_mayer 
79284409ddbSj_mayer #define ELF_CLASS       ELFCLASS64
79384409ddbSj_mayer 
79484409ddbSj_mayer #else
79584409ddbSj_mayer 
79667867308Sbellard #define ELF_CLASS       ELFCLASS32
797872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
79884409ddbSj_mayer 
79984409ddbSj_mayer #endif
80084409ddbSj_mayer 
80167867308Sbellard #define ELF_ARCH        EM_PPC
80267867308Sbellard 
803df84e4f3SNathan Froyd /* Feature masks for the Aux Vector Hardware Capabilities (AT_HWCAP).
804df84e4f3SNathan Froyd    See arch/powerpc/include/asm/cputable.h.  */
805df84e4f3SNathan Froyd enum {
8063efa9a67Smalc     QEMU_PPC_FEATURE_32 = 0x80000000,
8073efa9a67Smalc     QEMU_PPC_FEATURE_64 = 0x40000000,
8083efa9a67Smalc     QEMU_PPC_FEATURE_601_INSTR = 0x20000000,
8093efa9a67Smalc     QEMU_PPC_FEATURE_HAS_ALTIVEC = 0x10000000,
8103efa9a67Smalc     QEMU_PPC_FEATURE_HAS_FPU = 0x08000000,
8113efa9a67Smalc     QEMU_PPC_FEATURE_HAS_MMU = 0x04000000,
8123efa9a67Smalc     QEMU_PPC_FEATURE_HAS_4xxMAC = 0x02000000,
8133efa9a67Smalc     QEMU_PPC_FEATURE_UNIFIED_CACHE = 0x01000000,
8143efa9a67Smalc     QEMU_PPC_FEATURE_HAS_SPE = 0x00800000,
8153efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_SINGLE = 0x00400000,
8163efa9a67Smalc     QEMU_PPC_FEATURE_HAS_EFP_DOUBLE = 0x00200000,
8173efa9a67Smalc     QEMU_PPC_FEATURE_NO_TB = 0x00100000,
8183efa9a67Smalc     QEMU_PPC_FEATURE_POWER4 = 0x00080000,
8193efa9a67Smalc     QEMU_PPC_FEATURE_POWER5 = 0x00040000,
8203efa9a67Smalc     QEMU_PPC_FEATURE_POWER5_PLUS = 0x00020000,
8213efa9a67Smalc     QEMU_PPC_FEATURE_CELL = 0x00010000,
8223efa9a67Smalc     QEMU_PPC_FEATURE_BOOKE = 0x00008000,
8233efa9a67Smalc     QEMU_PPC_FEATURE_SMT = 0x00004000,
8243efa9a67Smalc     QEMU_PPC_FEATURE_ICACHE_SNOOP = 0x00002000,
8253efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_05 = 0x00001000,
8263efa9a67Smalc     QEMU_PPC_FEATURE_PA6T = 0x00000800,
8273efa9a67Smalc     QEMU_PPC_FEATURE_HAS_DFP = 0x00000400,
8283efa9a67Smalc     QEMU_PPC_FEATURE_POWER6_EXT = 0x00000200,
8293efa9a67Smalc     QEMU_PPC_FEATURE_ARCH_2_06 = 0x00000100,
8303efa9a67Smalc     QEMU_PPC_FEATURE_HAS_VSX = 0x00000080,
8313efa9a67Smalc     QEMU_PPC_FEATURE_PSERIES_PERFMON_COMPAT = 0x00000040,
832df84e4f3SNathan Froyd 
8333efa9a67Smalc     QEMU_PPC_FEATURE_TRUE_LE = 0x00000002,
8343efa9a67Smalc     QEMU_PPC_FEATURE_PPC_LE = 0x00000001,
835a60438ddSTom Musta 
836a60438ddSTom Musta     /* Feature definitions in AT_HWCAP2.  */
837a60438ddSTom Musta     QEMU_PPC_FEATURE2_ARCH_2_07 = 0x80000000, /* ISA 2.07 */
838a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_HTM = 0x40000000, /* Hardware Transactional Memory */
839a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_DSCR = 0x20000000, /* Data Stream Control Register */
840a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_EBB = 0x10000000, /* Event Base Branching */
841a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_ISEL = 0x08000000, /* Integer Select */
842a60438ddSTom Musta     QEMU_PPC_FEATURE2_HAS_TAR = 0x04000000, /* Target Address Register */
84324c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_VEC_CRYPTO = 0x02000000,
84424c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NOSC = 0x01000000,
845be0c46d4SSandipan Das     QEMU_PPC_FEATURE2_ARCH_3_00 = 0x00800000, /* ISA 3.00 */
84624c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HAS_IEEE128 = 0x00400000, /* VSX IEEE Bin Float 128-bit */
84724c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_DARN = 0x00200000, /* darn random number insn */
84824c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_SCV = 0x00100000, /* scv syscall */
84924c373ecSLaurent Vivier     QEMU_PPC_FEATURE2_HTM_NO_SUSPEND = 0x00080000, /* TM w/o suspended state */
85096c343ccSJoel Stanley     QEMU_PPC_FEATURE2_ARCH_3_1 = 0x00040000, /* ISA 3.1 */
85196c343ccSJoel Stanley     QEMU_PPC_FEATURE2_MMA = 0x00020000, /* Matrix-Multiply Assist */
852df84e4f3SNathan Froyd };
853df84e4f3SNathan Froyd 
854df84e4f3SNathan Froyd #define ELF_HWCAP get_elf_hwcap()
855df84e4f3SNathan Froyd 
856df84e4f3SNathan Froyd static uint32_t get_elf_hwcap(void)
857df84e4f3SNathan Froyd {
858a2247f8eSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
859df84e4f3SNathan Froyd     uint32_t features = 0;
860df84e4f3SNathan Froyd 
861df84e4f3SNathan Froyd     /* We don't have to be terribly complete here; the high points are
862df84e4f3SNathan Froyd        Altivec/FP/SPE support.  Anything else is just a bonus.  */
863df84e4f3SNathan Froyd #define GET_FEATURE(flag, feature)                                      \
864a2247f8eSAndreas Färber     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
86558eb5308SMichael Walle #define GET_FEATURE2(flags, feature) \
86658eb5308SMichael Walle     do { \
86758eb5308SMichael Walle         if ((cpu->env.insns_flags2 & flags) == flags) { \
86858eb5308SMichael Walle             features |= feature; \
86958eb5308SMichael Walle         } \
87058eb5308SMichael Walle     } while (0)
8713efa9a67Smalc     GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64);
8723efa9a67Smalc     GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU);
8733efa9a67Smalc     GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC);
8743efa9a67Smalc     GET_FEATURE(PPC_SPE, QEMU_PPC_FEATURE_HAS_SPE);
8753efa9a67Smalc     GET_FEATURE(PPC_SPE_SINGLE, QEMU_PPC_FEATURE_HAS_EFP_SINGLE);
8763efa9a67Smalc     GET_FEATURE(PPC_SPE_DOUBLE, QEMU_PPC_FEATURE_HAS_EFP_DOUBLE);
8773efa9a67Smalc     GET_FEATURE(PPC_BOOKE, QEMU_PPC_FEATURE_BOOKE);
8783efa9a67Smalc     GET_FEATURE(PPC_405_MAC, QEMU_PPC_FEATURE_HAS_4xxMAC);
8790e019746STom Musta     GET_FEATURE2(PPC2_DFP, QEMU_PPC_FEATURE_HAS_DFP);
8800e019746STom Musta     GET_FEATURE2(PPC2_VSX, QEMU_PPC_FEATURE_HAS_VSX);
8810e019746STom Musta     GET_FEATURE2((PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 |
8820e019746STom Musta                   PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206),
8830e019746STom Musta                   QEMU_PPC_FEATURE_ARCH_2_06);
884df84e4f3SNathan Froyd #undef GET_FEATURE
8850e019746STom Musta #undef GET_FEATURE2
886df84e4f3SNathan Froyd 
887df84e4f3SNathan Froyd     return features;
888df84e4f3SNathan Froyd }
889df84e4f3SNathan Froyd 
890a60438ddSTom Musta #define ELF_HWCAP2 get_elf_hwcap2()
891a60438ddSTom Musta 
892a60438ddSTom Musta static uint32_t get_elf_hwcap2(void)
893a60438ddSTom Musta {
894a60438ddSTom Musta     PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);
895a60438ddSTom Musta     uint32_t features = 0;
896a60438ddSTom Musta 
897a60438ddSTom Musta #define GET_FEATURE(flag, feature)                                      \
898a60438ddSTom Musta     do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0)
899a60438ddSTom Musta #define GET_FEATURE2(flag, feature)                                      \
900a60438ddSTom Musta     do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0)
901a60438ddSTom Musta 
902a60438ddSTom Musta     GET_FEATURE(PPC_ISEL, QEMU_PPC_FEATURE2_HAS_ISEL);
903a60438ddSTom Musta     GET_FEATURE2(PPC2_BCTAR_ISA207, QEMU_PPC_FEATURE2_HAS_TAR);
904a60438ddSTom Musta     GET_FEATURE2((PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
90524c373ecSLaurent Vivier                   PPC2_ISA207S), QEMU_PPC_FEATURE2_ARCH_2_07 |
90624c373ecSLaurent Vivier                   QEMU_PPC_FEATURE2_VEC_CRYPTO);
90724c373ecSLaurent Vivier     GET_FEATURE2(PPC2_ISA300, QEMU_PPC_FEATURE2_ARCH_3_00 |
9088a589aebSKhem Raj                  QEMU_PPC_FEATURE2_DARN | QEMU_PPC_FEATURE2_HAS_IEEE128);
90996c343ccSJoel Stanley     GET_FEATURE2(PPC2_ISA310, QEMU_PPC_FEATURE2_ARCH_3_1 |
91096c343ccSJoel Stanley                  QEMU_PPC_FEATURE2_MMA);
911a60438ddSTom Musta 
912a60438ddSTom Musta #undef GET_FEATURE
913a60438ddSTom Musta #undef GET_FEATURE2
914a60438ddSTom Musta 
915a60438ddSTom Musta     return features;
916a60438ddSTom Musta }
917a60438ddSTom Musta 
918f5155289Sbellard /*
919f5155289Sbellard  * The requirements here are:
920f5155289Sbellard  * - keep the final alignment of sp (sp & 0xf)
921f5155289Sbellard  * - make sure the 32-bit value at the first 16 byte aligned position of
922f5155289Sbellard  *   AUXV is greater than 16 for glibc compatibility.
923f5155289Sbellard  *   AT_IGNOREPPC is used for that.
924f5155289Sbellard  * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
925f5155289Sbellard  *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
926f5155289Sbellard  */
9270bccf03dSbellard #define DLINFO_ARCH_ITEMS       5
928f5155289Sbellard #define ARCH_DLINFO                                     \
929f5155289Sbellard     do {                                                \
930623e250aSTom Musta         PowerPCCPU *cpu = POWERPC_CPU(thread_cpu);              \
931f5155289Sbellard         /*                                              \
93282991bedSPeter Maydell          * Handle glibc compatibility: these magic entries must \
93382991bedSPeter Maydell          * be at the lowest addresses in the final auxv.        \
934f5155289Sbellard          */                                             \
9350bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
9360bccf03dSbellard         NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);        \
93782991bedSPeter Maydell         NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
93882991bedSPeter Maydell         NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
93982991bedSPeter Maydell         NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                 \
940f5155289Sbellard     } while (0)
941f5155289Sbellard 
94267867308Sbellard static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
94367867308Sbellard {
94467867308Sbellard     _regs->gpr[1] = infop->start_stack;
94574154d7eSThomas Huth #if defined(TARGET_PPC64)
946d90b94cdSDoug Kwan     if (get_ppc64_abi(infop) < 2) {
9472ccf97ecSPeter Maydell         uint64_t val;
9482ccf97ecSPeter Maydell         get_user_u64(val, infop->entry + 8);
9492ccf97ecSPeter Maydell         _regs->gpr[2] = val + infop->load_bias;
9502ccf97ecSPeter Maydell         get_user_u64(val, infop->entry);
9512ccf97ecSPeter Maydell         infop->entry = val + infop->load_bias;
952d90b94cdSDoug Kwan     } else {
953d90b94cdSDoug Kwan         _regs->gpr[12] = infop->entry;  /* r12 set to global entry address */
954d90b94cdSDoug Kwan     }
95584409ddbSj_mayer #endif
95667867308Sbellard     _regs->nip = infop->entry;
95767867308Sbellard }
95867867308Sbellard 
959e2f3e741SNathan Froyd /* See linux kernel: arch/powerpc/include/asm/elf.h.  */
960e2f3e741SNathan Froyd #define ELF_NREG 48
961e2f3e741SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
962e2f3e741SNathan Froyd 
96305390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *env)
964e2f3e741SNathan Froyd {
965e2f3e741SNathan Froyd     int i;
966e2f3e741SNathan Froyd     target_ulong ccr = 0;
967e2f3e741SNathan Froyd 
968e2f3e741SNathan Froyd     for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
96986cd7b2dSPaolo Bonzini         (*regs)[i] = tswapreg(env->gpr[i]);
970e2f3e741SNathan Froyd     }
971e2f3e741SNathan Froyd 
97286cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->nip);
97386cd7b2dSPaolo Bonzini     (*regs)[33] = tswapreg(env->msr);
97486cd7b2dSPaolo Bonzini     (*regs)[35] = tswapreg(env->ctr);
97586cd7b2dSPaolo Bonzini     (*regs)[36] = tswapreg(env->lr);
97610de0521SMatheus Ferst     (*regs)[37] = tswapreg(cpu_read_xer(env));
977e2f3e741SNathan Froyd 
9782060436aSHarsh Prateek Bora     ccr = ppc_get_cr(env);
97986cd7b2dSPaolo Bonzini     (*regs)[38] = tswapreg(ccr);
980e2f3e741SNathan Froyd }
981e2f3e741SNathan Froyd 
982e2f3e741SNathan Froyd #define USE_ELF_CORE_DUMP
98367867308Sbellard #define ELF_EXEC_PAGESIZE       4096
98467867308Sbellard 
98567867308Sbellard #endif
98667867308Sbellard 
9873418fe25SSong Gao #ifdef TARGET_LOONGARCH64
9883418fe25SSong Gao 
9893418fe25SSong Gao #define ELF_START_MMAP 0x80000000
9903418fe25SSong Gao 
9913418fe25SSong Gao #define ELF_CLASS   ELFCLASS64
9923418fe25SSong Gao #define ELF_ARCH    EM_LOONGARCH
993872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
9943418fe25SSong Gao 
9953418fe25SSong Gao #define elf_check_arch(x) ((x) == EM_LOONGARCH)
9963418fe25SSong Gao 
9973418fe25SSong Gao static inline void init_thread(struct target_pt_regs *regs,
9983418fe25SSong Gao                                struct image_info *infop)
9993418fe25SSong Gao {
10003418fe25SSong Gao     /*Set crmd PG,DA = 1,0 */
10013418fe25SSong Gao     regs->csr.crmd = 2 << 3;
10023418fe25SSong Gao     regs->csr.era = infop->entry;
10033418fe25SSong Gao     regs->regs[3] = infop->start_stack;
10043418fe25SSong Gao }
10053418fe25SSong Gao 
10063418fe25SSong Gao /* See linux kernel: arch/loongarch/include/asm/elf.h */
10073418fe25SSong Gao #define ELF_NREG 45
10083418fe25SSong Gao typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
10093418fe25SSong Gao 
10103418fe25SSong Gao enum {
10113418fe25SSong Gao     TARGET_EF_R0 = 0,
10123418fe25SSong Gao     TARGET_EF_CSR_ERA = TARGET_EF_R0 + 33,
10133418fe25SSong Gao     TARGET_EF_CSR_BADV = TARGET_EF_R0 + 34,
10143418fe25SSong Gao };
10153418fe25SSong Gao 
10163418fe25SSong Gao static void elf_core_copy_regs(target_elf_gregset_t *regs,
10173418fe25SSong Gao                                const CPULoongArchState *env)
10183418fe25SSong Gao {
10193418fe25SSong Gao     int i;
10203418fe25SSong Gao 
10213418fe25SSong Gao     (*regs)[TARGET_EF_R0] = 0;
10223418fe25SSong Gao 
10233418fe25SSong Gao     for (i = 1; i < ARRAY_SIZE(env->gpr); i++) {
10243418fe25SSong Gao         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->gpr[i]);
10253418fe25SSong Gao     }
10263418fe25SSong Gao 
10273418fe25SSong Gao     (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->pc);
10283418fe25SSong Gao     (*regs)[TARGET_EF_CSR_BADV] = tswapreg(env->CSR_BADV);
10293418fe25SSong Gao }
10303418fe25SSong Gao 
10313418fe25SSong Gao #define USE_ELF_CORE_DUMP
10323418fe25SSong Gao #define ELF_EXEC_PAGESIZE        4096
10333418fe25SSong Gao 
10343418fe25SSong Gao #define ELF_HWCAP get_elf_hwcap()
10353418fe25SSong Gao 
10363418fe25SSong Gao /* See arch/loongarch/include/uapi/asm/hwcap.h */
10373418fe25SSong Gao enum {
10383418fe25SSong Gao     HWCAP_LOONGARCH_CPUCFG   = (1 << 0),
10393418fe25SSong Gao     HWCAP_LOONGARCH_LAM      = (1 << 1),
10403418fe25SSong Gao     HWCAP_LOONGARCH_UAL      = (1 << 2),
10413418fe25SSong Gao     HWCAP_LOONGARCH_FPU      = (1 << 3),
10423418fe25SSong Gao     HWCAP_LOONGARCH_LSX      = (1 << 4),
10433418fe25SSong Gao     HWCAP_LOONGARCH_LASX     = (1 << 5),
10443418fe25SSong Gao     HWCAP_LOONGARCH_CRC32    = (1 << 6),
10453418fe25SSong Gao     HWCAP_LOONGARCH_COMPLEX  = (1 << 7),
10463418fe25SSong Gao     HWCAP_LOONGARCH_CRYPTO   = (1 << 8),
10473418fe25SSong Gao     HWCAP_LOONGARCH_LVZ      = (1 << 9),
10483418fe25SSong Gao     HWCAP_LOONGARCH_LBT_X86  = (1 << 10),
10493418fe25SSong Gao     HWCAP_LOONGARCH_LBT_ARM  = (1 << 11),
10503418fe25SSong Gao     HWCAP_LOONGARCH_LBT_MIPS = (1 << 12),
10513418fe25SSong Gao };
10523418fe25SSong Gao 
10533418fe25SSong Gao static uint32_t get_elf_hwcap(void)
10543418fe25SSong Gao {
10553418fe25SSong Gao     LoongArchCPU *cpu = LOONGARCH_CPU(thread_cpu);
10563418fe25SSong Gao     uint32_t hwcaps = 0;
10573418fe25SSong Gao 
10583418fe25SSong Gao     hwcaps |= HWCAP_LOONGARCH_CRC32;
10593418fe25SSong Gao 
10603418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[1], CPUCFG1, UAL)) {
10613418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_UAL;
10623418fe25SSong Gao     }
10633418fe25SSong Gao 
10643418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, FP)) {
10653418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_FPU;
10663418fe25SSong Gao     }
10673418fe25SSong Gao 
10683418fe25SSong Gao     if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LAM)) {
10693418fe25SSong Gao         hwcaps |= HWCAP_LOONGARCH_LAM;
10703418fe25SSong Gao     }
10713418fe25SSong Gao 
10723418fe25SSong Gao     return hwcaps;
10733418fe25SSong Gao }
10743418fe25SSong Gao 
10753418fe25SSong Gao #define ELF_PLATFORM "loongarch"
10763418fe25SSong Gao 
10773418fe25SSong Gao #endif /* TARGET_LOONGARCH64 */
10783418fe25SSong Gao 
1079048f6b4dSbellard #ifdef TARGET_MIPS
1080048f6b4dSbellard 
1081048f6b4dSbellard #define ELF_START_MMAP 0x80000000
1082048f6b4dSbellard 
1083388bb21aSths #ifdef TARGET_MIPS64
1084388bb21aSths #define ELF_CLASS   ELFCLASS64
1085388bb21aSths #else
1086048f6b4dSbellard #define ELF_CLASS   ELFCLASS32
1087388bb21aSths #endif
1088048f6b4dSbellard #define ELF_ARCH    EM_MIPS
1089872f3d04SRichard Henderson #define EXSTACK_DEFAULT true
1090048f6b4dSbellard 
1091ace3d654SCarlo Marcelo Arenas Belón #ifdef TARGET_ABI_MIPSN32
1092ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) ((x) & EF_MIPS_ABI2)
1093ace3d654SCarlo Marcelo Arenas Belón #else
1094ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (!((x) & EF_MIPS_ABI2))
1095ace3d654SCarlo Marcelo Arenas Belón #endif
1096ace3d654SCarlo Marcelo Arenas Belón 
1097fbf47c18SJiaxun Yang #define ELF_BASE_PLATFORM get_elf_base_platform()
1098fbf47c18SJiaxun Yang 
1099fbf47c18SJiaxun Yang #define MATCH_PLATFORM_INSN(_flags, _base_platform)      \
1100fbf47c18SJiaxun Yang     do { if ((cpu->env.insn_flags & (_flags)) == _flags) \
1101fbf47c18SJiaxun Yang     { return _base_platform; } } while (0)
1102fbf47c18SJiaxun Yang 
1103fbf47c18SJiaxun Yang static const char *get_elf_base_platform(void)
1104fbf47c18SJiaxun Yang {
1105fbf47c18SJiaxun Yang     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
1106fbf47c18SJiaxun Yang 
1107fbf47c18SJiaxun Yang     /* 64 bit ISAs goes first */
1108fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R6, "mips64r6");
1109fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R5, "mips64r5");
1110fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R2, "mips64r2");
1111fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS64R1, "mips64");
1112fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS5, "mips5");
1113fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS4, "mips4");
1114fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS3, "mips3");
1115fbf47c18SJiaxun Yang 
1116fbf47c18SJiaxun Yang     /* 32 bit ISAs */
1117fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R6, "mips32r6");
1118fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R5, "mips32r5");
1119fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R2, "mips32r2");
1120fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS32R1, "mips32");
1121fbf47c18SJiaxun Yang     MATCH_PLATFORM_INSN(CPU_MIPS2, "mips2");
1122fbf47c18SJiaxun Yang 
1123fbf47c18SJiaxun Yang     /* Fallback */
1124fbf47c18SJiaxun Yang     return "mips";
1125fbf47c18SJiaxun Yang }
1126fbf47c18SJiaxun Yang #undef MATCH_PLATFORM_INSN
1127fbf47c18SJiaxun Yang 
1128d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1129d97ef72eSRichard Henderson                                struct image_info *infop)
1130048f6b4dSbellard {
1131623a930eSths     regs->cp0_status = 2 << CP0St_KSU;
1132048f6b4dSbellard     regs->cp0_epc = infop->entry;
1133048f6b4dSbellard     regs->regs[29] = infop->start_stack;
1134048f6b4dSbellard }
1135048f6b4dSbellard 
113651e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/elf.h.  */
113751e52606SNathan Froyd #define ELF_NREG 45
113851e52606SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
113951e52606SNathan Froyd 
114051e52606SNathan Froyd /* See linux kernel: arch/mips/include/asm/reg.h.  */
114151e52606SNathan Froyd enum {
114251e52606SNathan Froyd #ifdef TARGET_MIPS64
114351e52606SNathan Froyd     TARGET_EF_R0 = 0,
114451e52606SNathan Froyd #else
114551e52606SNathan Froyd     TARGET_EF_R0 = 6,
114651e52606SNathan Froyd #endif
114751e52606SNathan Froyd     TARGET_EF_R26 = TARGET_EF_R0 + 26,
114851e52606SNathan Froyd     TARGET_EF_R27 = TARGET_EF_R0 + 27,
114951e52606SNathan Froyd     TARGET_EF_LO = TARGET_EF_R0 + 32,
115051e52606SNathan Froyd     TARGET_EF_HI = TARGET_EF_R0 + 33,
115151e52606SNathan Froyd     TARGET_EF_CP0_EPC = TARGET_EF_R0 + 34,
115251e52606SNathan Froyd     TARGET_EF_CP0_BADVADDR = TARGET_EF_R0 + 35,
115351e52606SNathan Froyd     TARGET_EF_CP0_STATUS = TARGET_EF_R0 + 36,
115451e52606SNathan Froyd     TARGET_EF_CP0_CAUSE = TARGET_EF_R0 + 37
115551e52606SNathan Froyd };
115651e52606SNathan Froyd 
115751e52606SNathan Froyd /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
115805390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMIPSState *env)
115951e52606SNathan Froyd {
116051e52606SNathan Froyd     int i;
116151e52606SNathan Froyd 
116251e52606SNathan Froyd     for (i = 0; i < TARGET_EF_R0; i++) {
116351e52606SNathan Froyd         (*regs)[i] = 0;
116451e52606SNathan Froyd     }
116551e52606SNathan Froyd     (*regs)[TARGET_EF_R0] = 0;
116651e52606SNathan Froyd 
116751e52606SNathan Froyd     for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
1168a29f998dSPaolo Bonzini         (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]);
116951e52606SNathan Froyd     }
117051e52606SNathan Froyd 
117151e52606SNathan Froyd     (*regs)[TARGET_EF_R26] = 0;
117251e52606SNathan Froyd     (*regs)[TARGET_EF_R27] = 0;
1173a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_LO] = tswapreg(env->active_tc.LO[0]);
1174a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_HI] = tswapreg(env->active_tc.HI[0]);
1175a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_EPC] = tswapreg(env->active_tc.PC);
1176a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_BADVADDR] = tswapreg(env->CP0_BadVAddr);
1177a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_STATUS] = tswapreg(env->CP0_Status);
1178a29f998dSPaolo Bonzini     (*regs)[TARGET_EF_CP0_CAUSE] = tswapreg(env->CP0_Cause);
117951e52606SNathan Froyd }
118051e52606SNathan Froyd 
118151e52606SNathan Froyd #define USE_ELF_CORE_DUMP
1182388bb21aSths #define ELF_EXEC_PAGESIZE        4096
1183388bb21aSths 
118446a1ee4fSJames Cowgill /* See arch/mips/include/uapi/asm/hwcap.h.  */
118546a1ee4fSJames Cowgill enum {
118646a1ee4fSJames Cowgill     HWCAP_MIPS_R6           = (1 << 0),
118746a1ee4fSJames Cowgill     HWCAP_MIPS_MSA          = (1 << 1),
11889ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_CRC32        = (1 << 2),
11899ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16       = (1 << 3),
11909ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MDMX         = (1 << 4),
11919ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS3D       = (1 << 5),
11929ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_SMARTMIPS    = (1 << 6),
11939ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP          = (1 << 7),
11949ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP2         = (1 << 8),
11959ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_DSP3         = (1 << 9),
11969ea313baSPhilippe Mathieu-Daudé     HWCAP_MIPS_MIPS16E2     = (1 << 10),
11979ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_MMI      = (1 << 11),
11989ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT      = (1 << 12),
11999ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_EXT2     = (1 << 13),
12009ea313baSPhilippe Mathieu-Daudé     HWCAP_LOONGSON_CPUCFG   = (1 << 14),
120146a1ee4fSJames Cowgill };
120246a1ee4fSJames Cowgill 
120346a1ee4fSJames Cowgill #define ELF_HWCAP get_elf_hwcap()
120446a1ee4fSJames Cowgill 
12057d9a3d96SPhilippe Mathieu-Daudé #define GET_FEATURE_INSN(_flag, _hwcap) \
12066dd97bfcSPhilippe Mathieu-Daudé     do { if (cpu->env.insn_flags & (_flag)) { hwcaps |= _hwcap; } } while (0)
12076dd97bfcSPhilippe Mathieu-Daudé 
1208388765a0SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_SET(_reg, _mask, _hwcap) \
1209388765a0SPhilippe Mathieu-Daudé     do { if (cpu->env._reg & (_mask)) { hwcaps |= _hwcap; } } while (0)
1210388765a0SPhilippe Mathieu-Daudé 
1211ce543844SPhilippe Mathieu-Daudé #define GET_FEATURE_REG_EQU(_reg, _start, _length, _val, _hwcap) \
1212ce543844SPhilippe Mathieu-Daudé     do { \
1213ce543844SPhilippe Mathieu-Daudé         if (extract32(cpu->env._reg, (_start), (_length)) == (_val)) { \
1214ce543844SPhilippe Mathieu-Daudé             hwcaps |= _hwcap; \
1215ce543844SPhilippe Mathieu-Daudé         } \
1216ce543844SPhilippe Mathieu-Daudé     } while (0)
1217ce543844SPhilippe Mathieu-Daudé 
121846a1ee4fSJames Cowgill static uint32_t get_elf_hwcap(void)
121946a1ee4fSJames Cowgill {
122046a1ee4fSJames Cowgill     MIPSCPU *cpu = MIPS_CPU(thread_cpu);
122146a1ee4fSJames Cowgill     uint32_t hwcaps = 0;
122246a1ee4fSJames Cowgill 
1223ce543844SPhilippe Mathieu-Daudé     GET_FEATURE_REG_EQU(CP0_Config0, CP0C0_AR, CP0C0_AR_LENGTH,
1224ce543844SPhilippe Mathieu-Daudé                         2, HWCAP_MIPS_R6);
1225388765a0SPhilippe Mathieu-Daudé     GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA);
122653673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LMMI, HWCAP_LOONGSON_MMI);
122753673d0fSPhilippe Mathieu-Daudé     GET_FEATURE_INSN(ASE_LEXT, HWCAP_LOONGSON_EXT);
122846a1ee4fSJames Cowgill 
122946a1ee4fSJames Cowgill     return hwcaps;
123046a1ee4fSJames Cowgill }
123146a1ee4fSJames Cowgill 
1232ce543844SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_EQU
1233388765a0SPhilippe Mathieu-Daudé #undef GET_FEATURE_REG_SET
12347d9a3d96SPhilippe Mathieu-Daudé #undef GET_FEATURE_INSN
12356dd97bfcSPhilippe Mathieu-Daudé 
1236048f6b4dSbellard #endif /* TARGET_MIPS */
1237048f6b4dSbellard 
1238b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
1239b779e29eSEdgar E. Iglesias 
1240b779e29eSEdgar E. Iglesias #define ELF_START_MMAP 0x80000000
1241b779e29eSEdgar E. Iglesias 
12420d5d4699SEdgar E. Iglesias #define elf_check_arch(x) ( (x) == EM_MICROBLAZE || (x) == EM_MICROBLAZE_OLD)
1243b779e29eSEdgar E. Iglesias 
1244b779e29eSEdgar E. Iglesias #define ELF_CLASS   ELFCLASS32
12450d5d4699SEdgar E. Iglesias #define ELF_ARCH    EM_MICROBLAZE
1246b779e29eSEdgar E. Iglesias 
1247d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1248d97ef72eSRichard Henderson                                struct image_info *infop)
1249b779e29eSEdgar E. Iglesias {
1250b779e29eSEdgar E. Iglesias     regs->pc = infop->entry;
1251b779e29eSEdgar E. Iglesias     regs->r1 = infop->start_stack;
1252b779e29eSEdgar E. Iglesias 
1253b779e29eSEdgar E. Iglesias }
1254b779e29eSEdgar E. Iglesias 
1255b779e29eSEdgar E. Iglesias #define ELF_EXEC_PAGESIZE        4096
1256b779e29eSEdgar E. Iglesias 
1257e4cbd44dSEdgar E. Iglesias #define USE_ELF_CORE_DUMP
1258e4cbd44dSEdgar E. Iglesias #define ELF_NREG 38
1259e4cbd44dSEdgar E. Iglesias typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1260e4cbd44dSEdgar E. Iglesias 
1261e4cbd44dSEdgar E. Iglesias /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
126205390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env)
1263e4cbd44dSEdgar E. Iglesias {
1264e4cbd44dSEdgar E. Iglesias     int i, pos = 0;
1265e4cbd44dSEdgar E. Iglesias 
1266e4cbd44dSEdgar E. Iglesias     for (i = 0; i < 32; i++) {
126786cd7b2dSPaolo Bonzini         (*regs)[pos++] = tswapreg(env->regs[i]);
1268e4cbd44dSEdgar E. Iglesias     }
1269e4cbd44dSEdgar E. Iglesias 
1270af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->pc);
12711074c0fbSRichard Henderson     (*regs)[pos++] = tswapreg(mb_cpu_read_msr(env));
1272af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1273af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->ear);
1274af20a93aSRichard Henderson     (*regs)[pos++] = 0;
1275af20a93aSRichard Henderson     (*regs)[pos++] = tswapreg(env->esr);
1276e4cbd44dSEdgar E. Iglesias }
1277e4cbd44dSEdgar E. Iglesias 
1278b779e29eSEdgar E. Iglesias #endif /* TARGET_MICROBLAZE */
1279b779e29eSEdgar E. Iglesias 
1280a0a839b6SMarek Vasut #ifdef TARGET_NIOS2
1281a0a839b6SMarek Vasut 
1282a0a839b6SMarek Vasut #define ELF_START_MMAP 0x80000000
1283a0a839b6SMarek Vasut 
1284a0a839b6SMarek Vasut #define elf_check_arch(x) ((x) == EM_ALTERA_NIOS2)
1285a0a839b6SMarek Vasut 
1286a0a839b6SMarek Vasut #define ELF_CLASS   ELFCLASS32
1287a0a839b6SMarek Vasut #define ELF_ARCH    EM_ALTERA_NIOS2
1288a0a839b6SMarek Vasut 
1289a0a839b6SMarek Vasut static void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1290a0a839b6SMarek Vasut {
1291a0a839b6SMarek Vasut     regs->ea = infop->entry;
1292a0a839b6SMarek Vasut     regs->sp = infop->start_stack;
1293a0a839b6SMarek Vasut }
1294a0a839b6SMarek Vasut 
1295f5ef0e51SRichard Henderson #define LO_COMMPAGE  TARGET_PAGE_SIZE
1296f5ef0e51SRichard Henderson 
1297f5ef0e51SRichard Henderson static bool init_guest_commpage(void)
1298f5ef0e51SRichard Henderson {
1299f5ef0e51SRichard Henderson     static const uint8_t kuser_page[4 + 2 * 64] = {
1300f5ef0e51SRichard Henderson         /* __kuser_helper_version */
1301f5ef0e51SRichard Henderson         [0x00] = 0x02, 0x00, 0x00, 0x00,
1302f5ef0e51SRichard Henderson 
1303f5ef0e51SRichard Henderson         /* __kuser_cmpxchg */
1304f5ef0e51SRichard Henderson         [0x04] = 0x3a, 0x6c, 0x3b, 0x00,  /* trap 16 */
1305f5ef0e51SRichard Henderson                  0x3a, 0x28, 0x00, 0xf8,  /* ret */
1306f5ef0e51SRichard Henderson 
1307f5ef0e51SRichard Henderson         /* __kuser_sigtramp */
1308f5ef0e51SRichard Henderson         [0x44] = 0xc4, 0x22, 0x80, 0x00,  /* movi r2, __NR_rt_sigreturn */
1309f5ef0e51SRichard Henderson                  0x3a, 0x68, 0x3b, 0x00,  /* trap 0 */
1310f5ef0e51SRichard Henderson     };
1311f5ef0e51SRichard Henderson 
1312f5ef0e51SRichard Henderson     void *want = g2h_untagged(LO_COMMPAGE & -qemu_host_page_size);
1313f5ef0e51SRichard Henderson     void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
1314f5ef0e51SRichard Henderson                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1315f5ef0e51SRichard Henderson 
1316f5ef0e51SRichard Henderson     if (addr == MAP_FAILED) {
1317f5ef0e51SRichard Henderson         perror("Allocating guest commpage");
1318f5ef0e51SRichard Henderson         exit(EXIT_FAILURE);
1319f5ef0e51SRichard Henderson     }
1320f5ef0e51SRichard Henderson     if (addr != want) {
1321f5ef0e51SRichard Henderson         return false;
1322f5ef0e51SRichard Henderson     }
1323f5ef0e51SRichard Henderson 
1324f5ef0e51SRichard Henderson     memcpy(addr, kuser_page, sizeof(kuser_page));
1325f5ef0e51SRichard Henderson 
1326f5ef0e51SRichard Henderson     if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
1327f5ef0e51SRichard Henderson         perror("Protecting guest commpage");
1328f5ef0e51SRichard Henderson         exit(EXIT_FAILURE);
1329f5ef0e51SRichard Henderson     }
1330f5ef0e51SRichard Henderson 
133149840a4aSRichard Henderson     page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
1332f5ef0e51SRichard Henderson                    PAGE_READ | PAGE_EXEC | PAGE_VALID);
1333f5ef0e51SRichard Henderson     return true;
1334f5ef0e51SRichard Henderson }
1335f5ef0e51SRichard Henderson 
1336a0a839b6SMarek Vasut #define ELF_EXEC_PAGESIZE        4096
1337a0a839b6SMarek Vasut 
1338a0a839b6SMarek Vasut #define USE_ELF_CORE_DUMP
1339a0a839b6SMarek Vasut #define ELF_NREG 49
1340a0a839b6SMarek Vasut typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1341a0a839b6SMarek Vasut 
1342a0a839b6SMarek Vasut /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
1343a0a839b6SMarek Vasut static void elf_core_copy_regs(target_elf_gregset_t *regs,
1344a0a839b6SMarek Vasut                                const CPUNios2State *env)
1345a0a839b6SMarek Vasut {
1346a0a839b6SMarek Vasut     int i;
1347a0a839b6SMarek Vasut 
1348a0a839b6SMarek Vasut     (*regs)[0] = -1;
1349a0a839b6SMarek Vasut     for (i = 1; i < 8; i++)    /* r0-r7 */
1350a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1351a0a839b6SMarek Vasut 
1352a0a839b6SMarek Vasut     for (i = 8; i < 16; i++)   /* r8-r15 */
1353a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i - 8]);
1354a0a839b6SMarek Vasut 
1355a0a839b6SMarek Vasut     for (i = 16; i < 24; i++)  /* r16-r23 */
1356a0a839b6SMarek Vasut         (*regs)[i] = tswapreg(env->regs[i + 7]);
1357a0a839b6SMarek Vasut     (*regs)[24] = -1;    /* R_ET */
1358a0a839b6SMarek Vasut     (*regs)[25] = -1;    /* R_BT */
1359a0a839b6SMarek Vasut     (*regs)[26] = tswapreg(env->regs[R_GP]);
1360a0a839b6SMarek Vasut     (*regs)[27] = tswapreg(env->regs[R_SP]);
1361a0a839b6SMarek Vasut     (*regs)[28] = tswapreg(env->regs[R_FP]);
1362a0a839b6SMarek Vasut     (*regs)[29] = tswapreg(env->regs[R_EA]);
1363a0a839b6SMarek Vasut     (*regs)[30] = -1;    /* R_SSTATUS */
1364a0a839b6SMarek Vasut     (*regs)[31] = tswapreg(env->regs[R_RA]);
1365a0a839b6SMarek Vasut 
136617a406eeSRichard Henderson     (*regs)[32] = tswapreg(env->pc);
1367a0a839b6SMarek Vasut 
1368a0a839b6SMarek Vasut     (*regs)[33] = -1; /* R_STATUS */
1369a0a839b6SMarek Vasut     (*regs)[34] = tswapreg(env->regs[CR_ESTATUS]);
1370a0a839b6SMarek Vasut 
1371a0a839b6SMarek Vasut     for (i = 35; i < 49; i++)    /* ... */
1372a0a839b6SMarek Vasut         (*regs)[i] = -1;
1373a0a839b6SMarek Vasut }
1374a0a839b6SMarek Vasut 
1375a0a839b6SMarek Vasut #endif /* TARGET_NIOS2 */
1376a0a839b6SMarek Vasut 
1377d962783eSJia Liu #ifdef TARGET_OPENRISC
1378d962783eSJia Liu 
1379d962783eSJia Liu #define ELF_START_MMAP 0x08000000
1380d962783eSJia Liu 
1381d962783eSJia Liu #define ELF_ARCH EM_OPENRISC
1382d962783eSJia Liu #define ELF_CLASS ELFCLASS32
1383d962783eSJia Liu #define ELF_DATA  ELFDATA2MSB
1384d962783eSJia Liu 
1385d962783eSJia Liu static inline void init_thread(struct target_pt_regs *regs,
1386d962783eSJia Liu                                struct image_info *infop)
1387d962783eSJia Liu {
1388d962783eSJia Liu     regs->pc = infop->entry;
1389d962783eSJia Liu     regs->gpr[1] = infop->start_stack;
1390d962783eSJia Liu }
1391d962783eSJia Liu 
1392d962783eSJia Liu #define USE_ELF_CORE_DUMP
1393d962783eSJia Liu #define ELF_EXEC_PAGESIZE 8192
1394d962783eSJia Liu 
1395d962783eSJia Liu /* See linux kernel arch/openrisc/include/asm/elf.h.  */
1396d962783eSJia Liu #define ELF_NREG 34 /* gprs and pc, sr */
1397d962783eSJia Liu typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1398d962783eSJia Liu 
1399d962783eSJia Liu static void elf_core_copy_regs(target_elf_gregset_t *regs,
1400d962783eSJia Liu                                const CPUOpenRISCState *env)
1401d962783eSJia Liu {
1402d962783eSJia Liu     int i;
1403d962783eSJia Liu 
1404d962783eSJia Liu     for (i = 0; i < 32; i++) {
1405d89e71e8SStafford Horne         (*regs)[i] = tswapreg(cpu_get_gpr(env, i));
1406d962783eSJia Liu     }
140786cd7b2dSPaolo Bonzini     (*regs)[32] = tswapreg(env->pc);
140884775c43SRichard Henderson     (*regs)[33] = tswapreg(cpu_get_sr(env));
1409d962783eSJia Liu }
1410d962783eSJia Liu #define ELF_HWCAP 0
1411d962783eSJia Liu #define ELF_PLATFORM NULL
1412d962783eSJia Liu 
1413d962783eSJia Liu #endif /* TARGET_OPENRISC */
1414d962783eSJia Liu 
1415fdf9b3e8Sbellard #ifdef TARGET_SH4
1416fdf9b3e8Sbellard 
1417fdf9b3e8Sbellard #define ELF_START_MMAP 0x80000000
1418fdf9b3e8Sbellard 
1419fdf9b3e8Sbellard #define ELF_CLASS ELFCLASS32
1420fdf9b3e8Sbellard #define ELF_ARCH  EM_SH
1421fdf9b3e8Sbellard 
1422d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1423d97ef72eSRichard Henderson                                struct image_info *infop)
1424fdf9b3e8Sbellard {
1425fdf9b3e8Sbellard     /* Check other registers XXXXX */
1426fdf9b3e8Sbellard     regs->pc = infop->entry;
1427072ae847Sths     regs->regs[15] = infop->start_stack;
1428fdf9b3e8Sbellard }
1429fdf9b3e8Sbellard 
14307631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/elf.h.  */
14317631c97eSNathan Froyd #define ELF_NREG 23
14327631c97eSNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
14337631c97eSNathan Froyd 
14347631c97eSNathan Froyd /* See linux kernel: arch/sh/include/asm/ptrace.h.  */
14357631c97eSNathan Froyd enum {
14367631c97eSNathan Froyd     TARGET_REG_PC = 16,
14377631c97eSNathan Froyd     TARGET_REG_PR = 17,
14387631c97eSNathan Froyd     TARGET_REG_SR = 18,
14397631c97eSNathan Froyd     TARGET_REG_GBR = 19,
14407631c97eSNathan Froyd     TARGET_REG_MACH = 20,
14417631c97eSNathan Froyd     TARGET_REG_MACL = 21,
14427631c97eSNathan Froyd     TARGET_REG_SYSCALL = 22
14437631c97eSNathan Froyd };
14447631c97eSNathan Froyd 
1445d97ef72eSRichard Henderson static inline void elf_core_copy_regs(target_elf_gregset_t *regs,
144605390248SAndreas Färber                                       const CPUSH4State *env)
14477631c97eSNathan Froyd {
14487631c97eSNathan Froyd     int i;
14497631c97eSNathan Froyd 
14507631c97eSNathan Froyd     for (i = 0; i < 16; i++) {
145172cd500bSPhilippe Mathieu-Daudé         (*regs)[i] = tswapreg(env->gregs[i]);
14527631c97eSNathan Froyd     }
14537631c97eSNathan Froyd 
145486cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
145586cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_PR] = tswapreg(env->pr);
145686cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_SR] = tswapreg(env->sr);
145786cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_GBR] = tswapreg(env->gbr);
145886cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACH] = tswapreg(env->mach);
145986cd7b2dSPaolo Bonzini     (*regs)[TARGET_REG_MACL] = tswapreg(env->macl);
14607631c97eSNathan Froyd     (*regs)[TARGET_REG_SYSCALL] = 0; /* FIXME */
14617631c97eSNathan Froyd }
14627631c97eSNathan Froyd 
14637631c97eSNathan Froyd #define USE_ELF_CORE_DUMP
1464fdf9b3e8Sbellard #define ELF_EXEC_PAGESIZE        4096
1465fdf9b3e8Sbellard 
1466e42fd944SRichard Henderson enum {
1467e42fd944SRichard Henderson     SH_CPU_HAS_FPU            = 0x0001, /* Hardware FPU support */
1468e42fd944SRichard Henderson     SH_CPU_HAS_P2_FLUSH_BUG   = 0x0002, /* Need to flush the cache in P2 area */
1469e42fd944SRichard Henderson     SH_CPU_HAS_MMU_PAGE_ASSOC = 0x0004, /* SH3: TLB way selection bit support */
1470e42fd944SRichard Henderson     SH_CPU_HAS_DSP            = 0x0008, /* SH-DSP: DSP support */
1471e42fd944SRichard Henderson     SH_CPU_HAS_PERF_COUNTER   = 0x0010, /* Hardware performance counters */
1472e42fd944SRichard Henderson     SH_CPU_HAS_PTEA           = 0x0020, /* PTEA register */
1473e42fd944SRichard Henderson     SH_CPU_HAS_LLSC           = 0x0040, /* movli.l/movco.l */
1474e42fd944SRichard Henderson     SH_CPU_HAS_L2_CACHE       = 0x0080, /* Secondary cache / URAM */
1475e42fd944SRichard Henderson     SH_CPU_HAS_OP32           = 0x0100, /* 32-bit instruction support */
1476e42fd944SRichard Henderson     SH_CPU_HAS_PTEAEX         = 0x0200, /* PTE ASID Extension support */
1477e42fd944SRichard Henderson };
1478e42fd944SRichard Henderson 
1479e42fd944SRichard Henderson #define ELF_HWCAP get_elf_hwcap()
1480e42fd944SRichard Henderson 
1481e42fd944SRichard Henderson static uint32_t get_elf_hwcap(void)
1482e42fd944SRichard Henderson {
1483e42fd944SRichard Henderson     SuperHCPU *cpu = SUPERH_CPU(thread_cpu);
1484e42fd944SRichard Henderson     uint32_t hwcap = 0;
1485e42fd944SRichard Henderson 
1486e42fd944SRichard Henderson     hwcap |= SH_CPU_HAS_FPU;
1487e42fd944SRichard Henderson 
1488e42fd944SRichard Henderson     if (cpu->env.features & SH_FEATURE_SH4A) {
1489e42fd944SRichard Henderson         hwcap |= SH_CPU_HAS_LLSC;
1490e42fd944SRichard Henderson     }
1491e42fd944SRichard Henderson 
1492e42fd944SRichard Henderson     return hwcap;
1493e42fd944SRichard Henderson }
1494e42fd944SRichard Henderson 
1495fdf9b3e8Sbellard #endif
1496fdf9b3e8Sbellard 
149748733d19Sths #ifdef TARGET_CRIS
149848733d19Sths 
149948733d19Sths #define ELF_START_MMAP 0x80000000
150048733d19Sths 
150148733d19Sths #define ELF_CLASS ELFCLASS32
150248733d19Sths #define ELF_ARCH  EM_CRIS
150348733d19Sths 
1504d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1505d97ef72eSRichard Henderson                                struct image_info *infop)
150648733d19Sths {
150748733d19Sths     regs->erp = infop->entry;
150848733d19Sths }
150948733d19Sths 
151048733d19Sths #define ELF_EXEC_PAGESIZE        8192
151148733d19Sths 
151248733d19Sths #endif
151348733d19Sths 
1514e6e5906bSpbrook #ifdef TARGET_M68K
1515e6e5906bSpbrook 
1516e6e5906bSpbrook #define ELF_START_MMAP 0x80000000
1517e6e5906bSpbrook 
1518e6e5906bSpbrook #define ELF_CLASS       ELFCLASS32
1519e6e5906bSpbrook #define ELF_ARCH        EM_68K
1520e6e5906bSpbrook 
1521e6e5906bSpbrook /* ??? Does this need to do anything?
1522e6e5906bSpbrook    #define ELF_PLAT_INIT(_r) */
1523e6e5906bSpbrook 
1524d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1525d97ef72eSRichard Henderson                                struct image_info *infop)
1526e6e5906bSpbrook {
1527e6e5906bSpbrook     regs->usp = infop->start_stack;
1528e6e5906bSpbrook     regs->sr = 0;
1529e6e5906bSpbrook     regs->pc = infop->entry;
1530e6e5906bSpbrook }
1531e6e5906bSpbrook 
15327a93cc55SNathan Froyd /* See linux kernel: arch/m68k/include/asm/elf.h.  */
15337a93cc55SNathan Froyd #define ELF_NREG 20
15347a93cc55SNathan Froyd typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
15357a93cc55SNathan Froyd 
153605390248SAndreas Färber static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUM68KState *env)
15377a93cc55SNathan Froyd {
153886cd7b2dSPaolo Bonzini     (*regs)[0] = tswapreg(env->dregs[1]);
153986cd7b2dSPaolo Bonzini     (*regs)[1] = tswapreg(env->dregs[2]);
154086cd7b2dSPaolo Bonzini     (*regs)[2] = tswapreg(env->dregs[3]);
154186cd7b2dSPaolo Bonzini     (*regs)[3] = tswapreg(env->dregs[4]);
154286cd7b2dSPaolo Bonzini     (*regs)[4] = tswapreg(env->dregs[5]);
154386cd7b2dSPaolo Bonzini     (*regs)[5] = tswapreg(env->dregs[6]);
154486cd7b2dSPaolo Bonzini     (*regs)[6] = tswapreg(env->dregs[7]);
154586cd7b2dSPaolo Bonzini     (*regs)[7] = tswapreg(env->aregs[0]);
154686cd7b2dSPaolo Bonzini     (*regs)[8] = tswapreg(env->aregs[1]);
154786cd7b2dSPaolo Bonzini     (*regs)[9] = tswapreg(env->aregs[2]);
154886cd7b2dSPaolo Bonzini     (*regs)[10] = tswapreg(env->aregs[3]);
154986cd7b2dSPaolo Bonzini     (*regs)[11] = tswapreg(env->aregs[4]);
155086cd7b2dSPaolo Bonzini     (*regs)[12] = tswapreg(env->aregs[5]);
155186cd7b2dSPaolo Bonzini     (*regs)[13] = tswapreg(env->aregs[6]);
155286cd7b2dSPaolo Bonzini     (*regs)[14] = tswapreg(env->dregs[0]);
155386cd7b2dSPaolo Bonzini     (*regs)[15] = tswapreg(env->aregs[7]);
155486cd7b2dSPaolo Bonzini     (*regs)[16] = tswapreg(env->dregs[0]); /* FIXME: orig_d0 */
155586cd7b2dSPaolo Bonzini     (*regs)[17] = tswapreg(env->sr);
155686cd7b2dSPaolo Bonzini     (*regs)[18] = tswapreg(env->pc);
15577a93cc55SNathan Froyd     (*regs)[19] = 0;  /* FIXME: regs->format | regs->vector */
15587a93cc55SNathan Froyd }
15597a93cc55SNathan Froyd 
15607a93cc55SNathan Froyd #define USE_ELF_CORE_DUMP
1561e6e5906bSpbrook #define ELF_EXEC_PAGESIZE       8192
1562e6e5906bSpbrook 
1563e6e5906bSpbrook #endif
1564e6e5906bSpbrook 
15657a3148a9Sj_mayer #ifdef TARGET_ALPHA
15667a3148a9Sj_mayer 
15677a3148a9Sj_mayer #define ELF_START_MMAP (0x30000000000ULL)
15687a3148a9Sj_mayer 
15697a3148a9Sj_mayer #define ELF_CLASS      ELFCLASS64
15707a3148a9Sj_mayer #define ELF_ARCH       EM_ALPHA
15717a3148a9Sj_mayer 
1572d97ef72eSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
1573d97ef72eSRichard Henderson                                struct image_info *infop)
15747a3148a9Sj_mayer {
15757a3148a9Sj_mayer     regs->pc = infop->entry;
15767a3148a9Sj_mayer     regs->ps = 8;
15777a3148a9Sj_mayer     regs->usp = infop->start_stack;
15787a3148a9Sj_mayer }
15797a3148a9Sj_mayer 
15807a3148a9Sj_mayer #define ELF_EXEC_PAGESIZE        8192
15817a3148a9Sj_mayer 
15827a3148a9Sj_mayer #endif /* TARGET_ALPHA */
15837a3148a9Sj_mayer 
1584a4c075f1SUlrich Hecht #ifdef TARGET_S390X
1585a4c075f1SUlrich Hecht 
1586a4c075f1SUlrich Hecht #define ELF_START_MMAP (0x20000000000ULL)
1587a4c075f1SUlrich Hecht 
1588a4c075f1SUlrich Hecht #define ELF_CLASS	ELFCLASS64
1589a4c075f1SUlrich Hecht #define ELF_DATA	ELFDATA2MSB
1590a4c075f1SUlrich Hecht #define ELF_ARCH	EM_S390
1591a4c075f1SUlrich Hecht 
15926d88baf1SDavid Hildenbrand #include "elf.h"
15936d88baf1SDavid Hildenbrand 
15946d88baf1SDavid Hildenbrand #define ELF_HWCAP get_elf_hwcap()
15956d88baf1SDavid Hildenbrand 
15966d88baf1SDavid Hildenbrand #define GET_FEATURE(_feat, _hwcap) \
15976d88baf1SDavid Hildenbrand     do { if (s390_has_feat(_feat)) { hwcap |= _hwcap; } } while (0)
15986d88baf1SDavid Hildenbrand 
1599e1b819c8SIlya Leoshkevich uint32_t get_elf_hwcap(void)
16006d88baf1SDavid Hildenbrand {
16016d88baf1SDavid Hildenbrand     /*
16026d88baf1SDavid Hildenbrand      * Let's assume we always have esan3 and zarch.
16036d88baf1SDavid Hildenbrand      * 31-bit processes can use 64-bit registers (high gprs).
16046d88baf1SDavid Hildenbrand      */
16056d88baf1SDavid Hildenbrand     uint32_t hwcap = HWCAP_S390_ESAN3 | HWCAP_S390_ZARCH | HWCAP_S390_HIGH_GPRS;
16066d88baf1SDavid Hildenbrand 
16076d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_STFLE, HWCAP_S390_STFLE);
16086d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_MSA, HWCAP_S390_MSA);
16096d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_LONG_DISPLACEMENT, HWCAP_S390_LDISP);
16106d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_EXTENDED_IMMEDIATE, HWCAP_S390_EIMM);
16116d88baf1SDavid Hildenbrand     if (s390_has_feat(S390_FEAT_EXTENDED_TRANSLATION_3) &&
16126d88baf1SDavid Hildenbrand         s390_has_feat(S390_FEAT_ETF3_ENH)) {
16136d88baf1SDavid Hildenbrand         hwcap |= HWCAP_S390_ETF3EH;
16146d88baf1SDavid Hildenbrand     }
16156d88baf1SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS);
1616da215c23SDavid Hildenbrand     GET_FEATURE(S390_FEAT_VECTOR_ENH, HWCAP_S390_VXRS_EXT);
16176d88baf1SDavid Hildenbrand 
16186d88baf1SDavid Hildenbrand     return hwcap;
16196d88baf1SDavid Hildenbrand }
16206d88baf1SDavid Hildenbrand 
1621e19807beSIlya Leoshkevich const char *elf_hwcap_str(uint32_t bit)
1622e19807beSIlya Leoshkevich {
1623e19807beSIlya Leoshkevich     static const char *hwcap_str[] = {
16247f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ESAN3]     = "esan3",
16257f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ZARCH]     = "zarch",
16267f114a58SIlya Leoshkevich         [HWCAP_S390_NR_STFLE]     = "stfle",
16277f114a58SIlya Leoshkevich         [HWCAP_S390_NR_MSA]       = "msa",
16287f114a58SIlya Leoshkevich         [HWCAP_S390_NR_LDISP]     = "ldisp",
16297f114a58SIlya Leoshkevich         [HWCAP_S390_NR_EIMM]      = "eimm",
16307f114a58SIlya Leoshkevich         [HWCAP_S390_NR_DFP]       = "dfp",
16317f114a58SIlya Leoshkevich         [HWCAP_S390_NR_HPAGE]     = "edat",
16327f114a58SIlya Leoshkevich         [HWCAP_S390_NR_ETF3EH]    = "etf3eh",
16337f114a58SIlya Leoshkevich         [HWCAP_S390_NR_HIGH_GPRS] = "highgprs",
16347f114a58SIlya Leoshkevich         [HWCAP_S390_NR_TE]        = "te",
16357f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS]      = "vx",
16367f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_BCD]  = "vxd",
16377f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_EXT]  = "vxe",
16387f114a58SIlya Leoshkevich         [HWCAP_S390_NR_GS]        = "gs",
16397f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_EXT2] = "vxe2",
16407f114a58SIlya Leoshkevich         [HWCAP_S390_NR_VXRS_PDE]  = "vxp",
16417f114a58SIlya Leoshkevich         [HWCAP_S390_NR_SORT]      = "sort",
16427f114a58SIlya Leoshkevich         [HWCAP_S390_NR_DFLT]      = "dflt",
16437f114a58SIlya Leoshkevich         [HWCAP_S390_NR_NNPA]      = "nnpa",
16447f114a58SIlya Leoshkevich         [HWCAP_S390_NR_PCI_MIO]   = "pcimio",
16457f114a58SIlya Leoshkevich         [HWCAP_S390_NR_SIE]       = "sie",
1646e19807beSIlya Leoshkevich     };
1647e19807beSIlya Leoshkevich 
1648e19807beSIlya Leoshkevich     return bit < ARRAY_SIZE(hwcap_str) ? hwcap_str[bit] : NULL;
1649e19807beSIlya Leoshkevich }
1650e19807beSIlya Leoshkevich 
1651a4c075f1SUlrich Hecht static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
1652a4c075f1SUlrich Hecht {
1653a4c075f1SUlrich Hecht     regs->psw.addr = infop->entry;
165478a1e153SIlya Leoshkevich     regs->psw.mask = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | \
165578a1e153SIlya Leoshkevich                      PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_MASK_64 | \
165678a1e153SIlya Leoshkevich                      PSW_MASK_32;
1657a4c075f1SUlrich Hecht     regs->gprs[15] = infop->start_stack;
1658a4c075f1SUlrich Hecht }
1659a4c075f1SUlrich Hecht 
16604a1e8931SIlya Leoshkevich /* See linux kernel: arch/s390/include/uapi/asm/ptrace.h (s390_regs).  */
16614a1e8931SIlya Leoshkevich #define ELF_NREG 27
16624a1e8931SIlya Leoshkevich typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
16634a1e8931SIlya Leoshkevich 
16644a1e8931SIlya Leoshkevich enum {
16654a1e8931SIlya Leoshkevich     TARGET_REG_PSWM = 0,
16664a1e8931SIlya Leoshkevich     TARGET_REG_PSWA = 1,
16674a1e8931SIlya Leoshkevich     TARGET_REG_GPRS = 2,
16684a1e8931SIlya Leoshkevich     TARGET_REG_ARS = 18,
16694a1e8931SIlya Leoshkevich     TARGET_REG_ORIG_R2 = 26,
16704a1e8931SIlya Leoshkevich };
16714a1e8931SIlya Leoshkevich 
16724a1e8931SIlya Leoshkevich static void elf_core_copy_regs(target_elf_gregset_t *regs,
16734a1e8931SIlya Leoshkevich                                const CPUS390XState *env)
16744a1e8931SIlya Leoshkevich {
16754a1e8931SIlya Leoshkevich     int i;
16764a1e8931SIlya Leoshkevich     uint32_t *aregs;
16774a1e8931SIlya Leoshkevich 
16784a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWM] = tswapreg(env->psw.mask);
16794a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_PSWA] = tswapreg(env->psw.addr);
16804a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
16814a1e8931SIlya Leoshkevich         (*regs)[TARGET_REG_GPRS + i] = tswapreg(env->regs[i]);
16824a1e8931SIlya Leoshkevich     }
16834a1e8931SIlya Leoshkevich     aregs = (uint32_t *)&((*regs)[TARGET_REG_ARS]);
16844a1e8931SIlya Leoshkevich     for (i = 0; i < 16; i++) {
16854a1e8931SIlya Leoshkevich         aregs[i] = tswap32(env->aregs[i]);
16864a1e8931SIlya Leoshkevich     }
16874a1e8931SIlya Leoshkevich     (*regs)[TARGET_REG_ORIG_R2] = 0;
16884a1e8931SIlya Leoshkevich }
16894a1e8931SIlya Leoshkevich 
16904a1e8931SIlya Leoshkevich #define USE_ELF_CORE_DUMP
16914a1e8931SIlya Leoshkevich #define ELF_EXEC_PAGESIZE 4096
16924a1e8931SIlya Leoshkevich 
1693a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
1694a4c075f1SUlrich Hecht 
169547ae93cdSMichael Clark #ifdef TARGET_RISCV
169647ae93cdSMichael Clark 
169747ae93cdSMichael Clark #define ELF_START_MMAP 0x80000000
169847ae93cdSMichael Clark #define ELF_ARCH  EM_RISCV
169947ae93cdSMichael Clark 
170047ae93cdSMichael Clark #ifdef TARGET_RISCV32
170147ae93cdSMichael Clark #define ELF_CLASS ELFCLASS32
170247ae93cdSMichael Clark #else
170347ae93cdSMichael Clark #define ELF_CLASS ELFCLASS64
170447ae93cdSMichael Clark #endif
170547ae93cdSMichael Clark 
1706cb46938cSKito Cheng #define ELF_HWCAP get_elf_hwcap()
1707cb46938cSKito Cheng 
1708cb46938cSKito Cheng static uint32_t get_elf_hwcap(void)
1709cb46938cSKito Cheng {
1710cb46938cSKito Cheng #define MISA_BIT(EXT) (1 << (EXT - 'A'))
1711cb46938cSKito Cheng     RISCVCPU *cpu = RISCV_CPU(thread_cpu);
1712cb46938cSKito Cheng     uint32_t mask = MISA_BIT('I') | MISA_BIT('M') | MISA_BIT('A')
17134333f092SNathan Egge                     | MISA_BIT('F') | MISA_BIT('D') | MISA_BIT('C')
17144333f092SNathan Egge                     | MISA_BIT('V');
1715cb46938cSKito Cheng 
1716e91a7227SRichard Henderson     return cpu->env.misa_ext & mask;
1717cb46938cSKito Cheng #undef MISA_BIT
1718cb46938cSKito Cheng }
1719cb46938cSKito Cheng 
172047ae93cdSMichael Clark static inline void init_thread(struct target_pt_regs *regs,
172147ae93cdSMichael Clark                                struct image_info *infop)
172247ae93cdSMichael Clark {
172347ae93cdSMichael Clark     regs->sepc = infop->entry;
172447ae93cdSMichael Clark     regs->sp = infop->start_stack;
172547ae93cdSMichael Clark }
172647ae93cdSMichael Clark 
172747ae93cdSMichael Clark #define ELF_EXEC_PAGESIZE 4096
172847ae93cdSMichael Clark 
172947ae93cdSMichael Clark #endif /* TARGET_RISCV */
173047ae93cdSMichael Clark 
17317c248bcdSRichard Henderson #ifdef TARGET_HPPA
17327c248bcdSRichard Henderson 
17337c248bcdSRichard Henderson #define ELF_START_MMAP  0x80000000
17347c248bcdSRichard Henderson #define ELF_CLASS       ELFCLASS32
17357c248bcdSRichard Henderson #define ELF_ARCH        EM_PARISC
17367c248bcdSRichard Henderson #define ELF_PLATFORM    "PARISC"
17377c248bcdSRichard Henderson #define STACK_GROWS_DOWN 0
17387c248bcdSRichard Henderson #define STACK_ALIGNMENT  64
17397c248bcdSRichard Henderson 
17407c248bcdSRichard Henderson static inline void init_thread(struct target_pt_regs *regs,
17417c248bcdSRichard Henderson                                struct image_info *infop)
17427c248bcdSRichard Henderson {
17437c248bcdSRichard Henderson     regs->iaoq[0] = infop->entry;
17447c248bcdSRichard Henderson     regs->iaoq[1] = infop->entry + 4;
17457c248bcdSRichard Henderson     regs->gr[23] = 0;
174660f1c801SRichard Henderson     regs->gr[24] = infop->argv;
174760f1c801SRichard Henderson     regs->gr[25] = infop->argc;
17487c248bcdSRichard Henderson     /* The top-of-stack contains a linkage buffer.  */
17497c248bcdSRichard Henderson     regs->gr[30] = infop->start_stack + 64;
17507c248bcdSRichard Henderson     regs->gr[31] = infop->entry;
17517c248bcdSRichard Henderson }
17527c248bcdSRichard Henderson 
1753eee816c0SRichard Henderson #define LO_COMMPAGE  0
1754eee816c0SRichard Henderson 
1755eee816c0SRichard Henderson static bool init_guest_commpage(void)
1756eee816c0SRichard Henderson {
1757eee816c0SRichard Henderson     void *want = g2h_untagged(LO_COMMPAGE);
1758eee816c0SRichard Henderson     void *addr = mmap(want, qemu_host_page_size, PROT_NONE,
1759eee816c0SRichard Henderson                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1760eee816c0SRichard Henderson 
1761eee816c0SRichard Henderson     if (addr == MAP_FAILED) {
1762eee816c0SRichard Henderson         perror("Allocating guest commpage");
1763eee816c0SRichard Henderson         exit(EXIT_FAILURE);
1764eee816c0SRichard Henderson     }
1765eee816c0SRichard Henderson     if (addr != want) {
1766eee816c0SRichard Henderson         return false;
1767eee816c0SRichard Henderson     }
1768eee816c0SRichard Henderson 
1769eee816c0SRichard Henderson     /*
1770eee816c0SRichard Henderson      * On Linux, page zero is normally marked execute only + gateway.
1771eee816c0SRichard Henderson      * Normal read or write is supposed to fail (thus PROT_NONE above),
1772eee816c0SRichard Henderson      * but specific offsets have kernel code mapped to raise permissions
1773eee816c0SRichard Henderson      * and implement syscalls.  Here, simply mark the page executable.
1774eee816c0SRichard Henderson      * Special case the entry points during translation (see do_page_zero).
1775eee816c0SRichard Henderson      */
177649840a4aSRichard Henderson     page_set_flags(LO_COMMPAGE, LO_COMMPAGE | ~TARGET_PAGE_MASK,
1777eee816c0SRichard Henderson                    PAGE_EXEC | PAGE_VALID);
1778eee816c0SRichard Henderson     return true;
1779eee816c0SRichard Henderson }
1780eee816c0SRichard Henderson 
17817c248bcdSRichard Henderson #endif /* TARGET_HPPA */
17827c248bcdSRichard Henderson 
1783ba7651fbSMax Filippov #ifdef TARGET_XTENSA
1784ba7651fbSMax Filippov 
1785ba7651fbSMax Filippov #define ELF_START_MMAP 0x20000000
1786ba7651fbSMax Filippov 
1787ba7651fbSMax Filippov #define ELF_CLASS       ELFCLASS32
1788ba7651fbSMax Filippov #define ELF_ARCH        EM_XTENSA
1789ba7651fbSMax Filippov 
1790ba7651fbSMax Filippov static inline void init_thread(struct target_pt_regs *regs,
1791ba7651fbSMax Filippov                                struct image_info *infop)
1792ba7651fbSMax Filippov {
1793ba7651fbSMax Filippov     regs->windowbase = 0;
1794ba7651fbSMax Filippov     regs->windowstart = 1;
1795ba7651fbSMax Filippov     regs->areg[1] = infop->start_stack;
1796ba7651fbSMax Filippov     regs->pc = infop->entry;
1797d2796be6SMax Filippov     if (info_is_fdpic(infop)) {
1798d2796be6SMax Filippov         regs->areg[4] = infop->loadmap_addr;
1799d2796be6SMax Filippov         regs->areg[5] = infop->interpreter_loadmap_addr;
1800d2796be6SMax Filippov         if (infop->interpreter_loadmap_addr) {
1801d2796be6SMax Filippov             regs->areg[6] = infop->interpreter_pt_dynamic_addr;
1802d2796be6SMax Filippov         } else {
1803d2796be6SMax Filippov             regs->areg[6] = infop->pt_dynamic_addr;
1804d2796be6SMax Filippov         }
1805d2796be6SMax Filippov     }
1806ba7651fbSMax Filippov }
1807ba7651fbSMax Filippov 
1808ba7651fbSMax Filippov /* See linux kernel: arch/xtensa/include/asm/elf.h.  */
1809ba7651fbSMax Filippov #define ELF_NREG 128
1810ba7651fbSMax Filippov typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
1811ba7651fbSMax Filippov 
1812ba7651fbSMax Filippov enum {
1813ba7651fbSMax Filippov     TARGET_REG_PC,
1814ba7651fbSMax Filippov     TARGET_REG_PS,
1815ba7651fbSMax Filippov     TARGET_REG_LBEG,
1816ba7651fbSMax Filippov     TARGET_REG_LEND,
1817ba7651fbSMax Filippov     TARGET_REG_LCOUNT,
1818ba7651fbSMax Filippov     TARGET_REG_SAR,
1819ba7651fbSMax Filippov     TARGET_REG_WINDOWSTART,
1820ba7651fbSMax Filippov     TARGET_REG_WINDOWBASE,
1821ba7651fbSMax Filippov     TARGET_REG_THREADPTR,
1822ba7651fbSMax Filippov     TARGET_REG_AR0 = 64,
1823ba7651fbSMax Filippov };
1824ba7651fbSMax Filippov 
1825ba7651fbSMax Filippov static void elf_core_copy_regs(target_elf_gregset_t *regs,
1826ba7651fbSMax Filippov                                const CPUXtensaState *env)
1827ba7651fbSMax Filippov {
1828ba7651fbSMax Filippov     unsigned i;
1829ba7651fbSMax Filippov 
1830ba7651fbSMax Filippov     (*regs)[TARGET_REG_PC] = tswapreg(env->pc);
1831ba7651fbSMax Filippov     (*regs)[TARGET_REG_PS] = tswapreg(env->sregs[PS] & ~PS_EXCM);
1832ba7651fbSMax Filippov     (*regs)[TARGET_REG_LBEG] = tswapreg(env->sregs[LBEG]);
1833ba7651fbSMax Filippov     (*regs)[TARGET_REG_LEND] = tswapreg(env->sregs[LEND]);
1834ba7651fbSMax Filippov     (*regs)[TARGET_REG_LCOUNT] = tswapreg(env->sregs[LCOUNT]);
1835ba7651fbSMax Filippov     (*regs)[TARGET_REG_SAR] = tswapreg(env->sregs[SAR]);
1836ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWSTART] = tswapreg(env->sregs[WINDOW_START]);
1837ba7651fbSMax Filippov     (*regs)[TARGET_REG_WINDOWBASE] = tswapreg(env->sregs[WINDOW_BASE]);
1838ba7651fbSMax Filippov     (*regs)[TARGET_REG_THREADPTR] = tswapreg(env->uregs[THREADPTR]);
1839ba7651fbSMax Filippov     xtensa_sync_phys_from_window((CPUXtensaState *)env);
1840ba7651fbSMax Filippov     for (i = 0; i < env->config->nareg; ++i) {
1841ba7651fbSMax Filippov         (*regs)[TARGET_REG_AR0 + i] = tswapreg(env->phys_regs[i]);
1842ba7651fbSMax Filippov     }
1843ba7651fbSMax Filippov }
1844ba7651fbSMax Filippov 
1845ba7651fbSMax Filippov #define USE_ELF_CORE_DUMP
1846ba7651fbSMax Filippov #define ELF_EXEC_PAGESIZE       4096
1847ba7651fbSMax Filippov 
1848ba7651fbSMax Filippov #endif /* TARGET_XTENSA */
1849ba7651fbSMax Filippov 
1850d2a56bd2STaylor Simpson #ifdef TARGET_HEXAGON
1851d2a56bd2STaylor Simpson 
1852d2a56bd2STaylor Simpson #define ELF_START_MMAP 0x20000000
1853d2a56bd2STaylor Simpson 
1854d2a56bd2STaylor Simpson #define ELF_CLASS       ELFCLASS32
1855d2a56bd2STaylor Simpson #define ELF_ARCH        EM_HEXAGON
1856d2a56bd2STaylor Simpson 
1857d2a56bd2STaylor Simpson static inline void init_thread(struct target_pt_regs *regs,
1858d2a56bd2STaylor Simpson                                struct image_info *infop)
1859d2a56bd2STaylor Simpson {
1860d2a56bd2STaylor Simpson     regs->sepc = infop->entry;
1861d2a56bd2STaylor Simpson     regs->sp = infop->start_stack;
1862d2a56bd2STaylor Simpson }
1863d2a56bd2STaylor Simpson 
1864d2a56bd2STaylor Simpson #endif /* TARGET_HEXAGON */
1865d2a56bd2STaylor Simpson 
1866fcdc0ab4SJiaxun Yang #ifndef ELF_BASE_PLATFORM
1867fcdc0ab4SJiaxun Yang #define ELF_BASE_PLATFORM (NULL)
1868fcdc0ab4SJiaxun Yang #endif
1869fcdc0ab4SJiaxun Yang 
187015338fd7Sbellard #ifndef ELF_PLATFORM
187115338fd7Sbellard #define ELF_PLATFORM (NULL)
187215338fd7Sbellard #endif
187315338fd7Sbellard 
187475be901cSPeter Crosthwaite #ifndef ELF_MACHINE
187575be901cSPeter Crosthwaite #define ELF_MACHINE ELF_ARCH
187675be901cSPeter Crosthwaite #endif
187775be901cSPeter Crosthwaite 
1878d276a604SPeter Crosthwaite #ifndef elf_check_arch
1879d276a604SPeter Crosthwaite #define elf_check_arch(x) ((x) == ELF_ARCH)
1880d276a604SPeter Crosthwaite #endif
1881d276a604SPeter Crosthwaite 
1882ace3d654SCarlo Marcelo Arenas Belón #ifndef elf_check_abi
1883ace3d654SCarlo Marcelo Arenas Belón #define elf_check_abi(x) (1)
1884ace3d654SCarlo Marcelo Arenas Belón #endif
1885ace3d654SCarlo Marcelo Arenas Belón 
188615338fd7Sbellard #ifndef ELF_HWCAP
188715338fd7Sbellard #define ELF_HWCAP 0
188815338fd7Sbellard #endif
188915338fd7Sbellard 
18907c4ee5bcSRichard Henderson #ifndef STACK_GROWS_DOWN
18917c4ee5bcSRichard Henderson #define STACK_GROWS_DOWN 1
18927c4ee5bcSRichard Henderson #endif
18937c4ee5bcSRichard Henderson 
18947c4ee5bcSRichard Henderson #ifndef STACK_ALIGNMENT
18957c4ee5bcSRichard Henderson #define STACK_ALIGNMENT 16
18967c4ee5bcSRichard Henderson #endif
18977c4ee5bcSRichard Henderson 
1898992f48a0Sblueswir1 #ifdef TARGET_ABI32
1899cb33da57Sblueswir1 #undef ELF_CLASS
1900992f48a0Sblueswir1 #define ELF_CLASS ELFCLASS32
1901cb33da57Sblueswir1 #undef bswaptls
1902cb33da57Sblueswir1 #define bswaptls(ptr) bswap32s(ptr)
1903cb33da57Sblueswir1 #endif
1904cb33da57Sblueswir1 
1905872f3d04SRichard Henderson #ifndef EXSTACK_DEFAULT
1906872f3d04SRichard Henderson #define EXSTACK_DEFAULT false
1907872f3d04SRichard Henderson #endif
1908872f3d04SRichard Henderson 
190931e31b8aSbellard #include "elf.h"
191009bfb054Sbellard 
1911e8384b37SRichard Henderson /* We must delay the following stanzas until after "elf.h". */
1912e8384b37SRichard Henderson #if defined(TARGET_AARCH64)
1913e8384b37SRichard Henderson 
1914e8384b37SRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
1915e8384b37SRichard Henderson                                     const uint32_t *data,
1916e8384b37SRichard Henderson                                     struct image_info *info,
1917e8384b37SRichard Henderson                                     Error **errp)
1918e8384b37SRichard Henderson {
1919e8384b37SRichard Henderson     if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
1920e8384b37SRichard Henderson         if (pr_datasz != sizeof(uint32_t)) {
1921e8384b37SRichard Henderson             error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
1922e8384b37SRichard Henderson             return false;
1923e8384b37SRichard Henderson         }
1924e8384b37SRichard Henderson         /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
1925e8384b37SRichard Henderson         info->note_flags = *data;
1926e8384b37SRichard Henderson     }
1927e8384b37SRichard Henderson     return true;
1928e8384b37SRichard Henderson }
1929e8384b37SRichard Henderson #define ARCH_USE_GNU_PROPERTY 1
1930e8384b37SRichard Henderson 
1931e8384b37SRichard Henderson #else
1932e8384b37SRichard Henderson 
193383f990ebSRichard Henderson static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
193483f990ebSRichard Henderson                                     const uint32_t *data,
193583f990ebSRichard Henderson                                     struct image_info *info,
193683f990ebSRichard Henderson                                     Error **errp)
193783f990ebSRichard Henderson {
193883f990ebSRichard Henderson     g_assert_not_reached();
193983f990ebSRichard Henderson }
194083f990ebSRichard Henderson #define ARCH_USE_GNU_PROPERTY 0
194183f990ebSRichard Henderson 
1942e8384b37SRichard Henderson #endif
1943e8384b37SRichard Henderson 
194409bfb054Sbellard struct exec
194509bfb054Sbellard {
194609bfb054Sbellard     unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
194709bfb054Sbellard     unsigned int a_text;   /* length of text, in bytes */
194809bfb054Sbellard     unsigned int a_data;   /* length of data, in bytes */
194909bfb054Sbellard     unsigned int a_bss;    /* length of uninitialized data area, in bytes */
195009bfb054Sbellard     unsigned int a_syms;   /* length of symbol table data in file, in bytes */
195109bfb054Sbellard     unsigned int a_entry;  /* start address */
195209bfb054Sbellard     unsigned int a_trsize; /* length of relocation info for text, in bytes */
195309bfb054Sbellard     unsigned int a_drsize; /* length of relocation info for data, in bytes */
195409bfb054Sbellard };
195509bfb054Sbellard 
195609bfb054Sbellard 
195709bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
195809bfb054Sbellard #define OMAGIC 0407
195909bfb054Sbellard #define NMAGIC 0410
196009bfb054Sbellard #define ZMAGIC 0413
196109bfb054Sbellard #define QMAGIC 0314
196209bfb054Sbellard 
1963e0d1673dSLirong Yuan #define DLINFO_ITEMS 16
196431e31b8aSbellard 
196509bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
196609bfb054Sbellard {
196709bfb054Sbellard     memcpy(to, from, n);
196809bfb054Sbellard }
196909bfb054Sbellard 
197031e31b8aSbellard #ifdef BSWAP_NEEDED
197192a31b1fSbellard static void bswap_ehdr(struct elfhdr *ehdr)
197231e31b8aSbellard {
197331e31b8aSbellard     bswap16s(&ehdr->e_type);            /* Object file type */
197431e31b8aSbellard     bswap16s(&ehdr->e_machine);         /* Architecture */
197531e31b8aSbellard     bswap32s(&ehdr->e_version);         /* Object file version */
197692a31b1fSbellard     bswaptls(&ehdr->e_entry);           /* Entry point virtual address */
197792a31b1fSbellard     bswaptls(&ehdr->e_phoff);           /* Program header table file offset */
197892a31b1fSbellard     bswaptls(&ehdr->e_shoff);           /* Section header table file offset */
197931e31b8aSbellard     bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
198031e31b8aSbellard     bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
198131e31b8aSbellard     bswap16s(&ehdr->e_phentsize);       /* Program header table entry size */
198231e31b8aSbellard     bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
198331e31b8aSbellard     bswap16s(&ehdr->e_shentsize);       /* Section header table entry size */
198431e31b8aSbellard     bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
198531e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);        /* Section header string table index */
198631e31b8aSbellard }
198731e31b8aSbellard 
1988991f8f0cSRichard Henderson static void bswap_phdr(struct elf_phdr *phdr, int phnum)
198931e31b8aSbellard {
1990991f8f0cSRichard Henderson     int i;
1991991f8f0cSRichard Henderson     for (i = 0; i < phnum; ++i, ++phdr) {
199231e31b8aSbellard         bswap32s(&phdr->p_type);        /* Segment type */
1993991f8f0cSRichard Henderson         bswap32s(&phdr->p_flags);       /* Segment flags */
199492a31b1fSbellard         bswaptls(&phdr->p_offset);      /* Segment file offset */
199592a31b1fSbellard         bswaptls(&phdr->p_vaddr);       /* Segment virtual address */
199692a31b1fSbellard         bswaptls(&phdr->p_paddr);       /* Segment physical address */
199792a31b1fSbellard         bswaptls(&phdr->p_filesz);      /* Segment size in file */
199892a31b1fSbellard         bswaptls(&phdr->p_memsz);       /* Segment size in memory */
199992a31b1fSbellard         bswaptls(&phdr->p_align);       /* Segment alignment */
200031e31b8aSbellard     }
2001991f8f0cSRichard Henderson }
2002689f936fSbellard 
2003991f8f0cSRichard Henderson static void bswap_shdr(struct elf_shdr *shdr, int shnum)
2004689f936fSbellard {
2005991f8f0cSRichard Henderson     int i;
2006991f8f0cSRichard Henderson     for (i = 0; i < shnum; ++i, ++shdr) {
2007689f936fSbellard         bswap32s(&shdr->sh_name);
2008689f936fSbellard         bswap32s(&shdr->sh_type);
200992a31b1fSbellard         bswaptls(&shdr->sh_flags);
201092a31b1fSbellard         bswaptls(&shdr->sh_addr);
201192a31b1fSbellard         bswaptls(&shdr->sh_offset);
201292a31b1fSbellard         bswaptls(&shdr->sh_size);
2013689f936fSbellard         bswap32s(&shdr->sh_link);
2014689f936fSbellard         bswap32s(&shdr->sh_info);
201592a31b1fSbellard         bswaptls(&shdr->sh_addralign);
201692a31b1fSbellard         bswaptls(&shdr->sh_entsize);
2017689f936fSbellard     }
2018991f8f0cSRichard Henderson }
2019689f936fSbellard 
20207a3148a9Sj_mayer static void bswap_sym(struct elf_sym *sym)
2021689f936fSbellard {
2022689f936fSbellard     bswap32s(&sym->st_name);
20237a3148a9Sj_mayer     bswaptls(&sym->st_value);
20247a3148a9Sj_mayer     bswaptls(&sym->st_size);
2025689f936fSbellard     bswap16s(&sym->st_shndx);
2026689f936fSbellard }
20275dd0db52SStefan Markovic 
20285dd0db52SStefan Markovic #ifdef TARGET_MIPS
20295dd0db52SStefan Markovic static void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags)
20305dd0db52SStefan Markovic {
20315dd0db52SStefan Markovic     bswap16s(&abiflags->version);
20325dd0db52SStefan Markovic     bswap32s(&abiflags->ases);
20335dd0db52SStefan Markovic     bswap32s(&abiflags->isa_ext);
20345dd0db52SStefan Markovic     bswap32s(&abiflags->flags1);
20355dd0db52SStefan Markovic     bswap32s(&abiflags->flags2);
20365dd0db52SStefan Markovic }
20375dd0db52SStefan Markovic #endif
2038991f8f0cSRichard Henderson #else
2039991f8f0cSRichard Henderson static inline void bswap_ehdr(struct elfhdr *ehdr) { }
2040991f8f0cSRichard Henderson static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { }
2041991f8f0cSRichard Henderson static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { }
2042991f8f0cSRichard Henderson static inline void bswap_sym(struct elf_sym *sym) { }
20435dd0db52SStefan Markovic #ifdef TARGET_MIPS
20445dd0db52SStefan Markovic static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { }
20455dd0db52SStefan Markovic #endif
204631e31b8aSbellard #endif
204731e31b8aSbellard 
2048edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
20499349b4f9SAndreas Färber static int elf_core_dump(int, const CPUArchState *);
2050edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
2051682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
2052edf8e2afSMika Westerberg 
20539058abddSRichard Henderson /* Verify the portions of EHDR within E_IDENT for the target.
20549058abddSRichard Henderson    This can be performed before bswapping the entire header.  */
20559058abddSRichard Henderson static bool elf_check_ident(struct elfhdr *ehdr)
20569058abddSRichard Henderson {
20579058abddSRichard Henderson     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
20589058abddSRichard Henderson             && ehdr->e_ident[EI_MAG1] == ELFMAG1
20599058abddSRichard Henderson             && ehdr->e_ident[EI_MAG2] == ELFMAG2
20609058abddSRichard Henderson             && ehdr->e_ident[EI_MAG3] == ELFMAG3
20619058abddSRichard Henderson             && ehdr->e_ident[EI_CLASS] == ELF_CLASS
20629058abddSRichard Henderson             && ehdr->e_ident[EI_DATA] == ELF_DATA
20639058abddSRichard Henderson             && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
20649058abddSRichard Henderson }
20659058abddSRichard Henderson 
20669058abddSRichard Henderson /* Verify the portions of EHDR outside of E_IDENT for the target.
20679058abddSRichard Henderson    This has to wait until after bswapping the header.  */
20689058abddSRichard Henderson static bool elf_check_ehdr(struct elfhdr *ehdr)
20699058abddSRichard Henderson {
20709058abddSRichard Henderson     return (elf_check_arch(ehdr->e_machine)
2071ace3d654SCarlo Marcelo Arenas Belón             && elf_check_abi(ehdr->e_flags)
20729058abddSRichard Henderson             && ehdr->e_ehsize == sizeof(struct elfhdr)
20739058abddSRichard Henderson             && ehdr->e_phentsize == sizeof(struct elf_phdr)
20749058abddSRichard Henderson             && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
20759058abddSRichard Henderson }
20769058abddSRichard Henderson 
207731e31b8aSbellard /*
2078e5fe0c52Spbrook  * 'copy_elf_strings()' copies argument/envelope strings from user
207931e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
208031e31b8aSbellard  * to be put directly into the top of new user memory.
208131e31b8aSbellard  *
208231e31b8aSbellard  */
208359baae9aSStefan Brüns static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch,
208459baae9aSStefan Brüns                                   abi_ulong p, abi_ulong stack_limit)
208531e31b8aSbellard {
208659baae9aSStefan Brüns     char *tmp;
20877c4ee5bcSRichard Henderson     int len, i;
208859baae9aSStefan Brüns     abi_ulong top = p;
208931e31b8aSbellard 
209031e31b8aSbellard     if (!p) {
209131e31b8aSbellard         return 0;       /* bullet-proofing */
209231e31b8aSbellard     }
209359baae9aSStefan Brüns 
20947c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
20957c4ee5bcSRichard Henderson         int offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
20967c4ee5bcSRichard Henderson         for (i = argc - 1; i >= 0; --i) {
20977c4ee5bcSRichard Henderson             tmp = argv[i];
2098edf779ffSbellard             if (!tmp) {
209931e31b8aSbellard                 fprintf(stderr, "VFS: argc is wrong");
210031e31b8aSbellard                 exit(-1);
210131e31b8aSbellard             }
210259baae9aSStefan Brüns             len = strlen(tmp) + 1;
210359baae9aSStefan Brüns             tmp += len;
210459baae9aSStefan Brüns 
210559baae9aSStefan Brüns             if (len > (p - stack_limit)) {
210631e31b8aSbellard                 return 0;
210731e31b8aSbellard             }
210831e31b8aSbellard             while (len) {
210931e31b8aSbellard                 int bytes_to_copy = (len > offset) ? offset : len;
211031e31b8aSbellard                 tmp -= bytes_to_copy;
211131e31b8aSbellard                 p -= bytes_to_copy;
211231e31b8aSbellard                 offset -= bytes_to_copy;
211331e31b8aSbellard                 len -= bytes_to_copy;
211459baae9aSStefan Brüns 
211559baae9aSStefan Brüns                 memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
211659baae9aSStefan Brüns 
211759baae9aSStefan Brüns                 if (offset == 0) {
211859baae9aSStefan Brüns                     memcpy_to_target(p, scratch, top - p);
211959baae9aSStefan Brüns                     top = p;
212059baae9aSStefan Brüns                     offset = TARGET_PAGE_SIZE;
212131e31b8aSbellard                 }
212231e31b8aSbellard             }
212331e31b8aSbellard         }
21247c4ee5bcSRichard Henderson         if (p != top) {
212559baae9aSStefan Brüns             memcpy_to_target(p, scratch + offset, top - p);
212659baae9aSStefan Brüns         }
21277c4ee5bcSRichard Henderson     } else {
21287c4ee5bcSRichard Henderson         int remaining = TARGET_PAGE_SIZE - (p % TARGET_PAGE_SIZE);
21297c4ee5bcSRichard Henderson         for (i = 0; i < argc; ++i) {
21307c4ee5bcSRichard Henderson             tmp = argv[i];
21317c4ee5bcSRichard Henderson             if (!tmp) {
21327c4ee5bcSRichard Henderson                 fprintf(stderr, "VFS: argc is wrong");
21337c4ee5bcSRichard Henderson                 exit(-1);
21347c4ee5bcSRichard Henderson             }
21357c4ee5bcSRichard Henderson             len = strlen(tmp) + 1;
21367c4ee5bcSRichard Henderson             if (len > (stack_limit - p)) {
21377c4ee5bcSRichard Henderson                 return 0;
21387c4ee5bcSRichard Henderson             }
21397c4ee5bcSRichard Henderson             while (len) {
21407c4ee5bcSRichard Henderson                 int bytes_to_copy = (len > remaining) ? remaining : len;
21417c4ee5bcSRichard Henderson 
21427c4ee5bcSRichard Henderson                 memcpy_fromfs(scratch + (p - top), tmp, bytes_to_copy);
21437c4ee5bcSRichard Henderson 
21447c4ee5bcSRichard Henderson                 tmp += bytes_to_copy;
21457c4ee5bcSRichard Henderson                 remaining -= bytes_to_copy;
21467c4ee5bcSRichard Henderson                 p += bytes_to_copy;
21477c4ee5bcSRichard Henderson                 len -= bytes_to_copy;
21487c4ee5bcSRichard Henderson 
21497c4ee5bcSRichard Henderson                 if (remaining == 0) {
21507c4ee5bcSRichard Henderson                     memcpy_to_target(top, scratch, p - top);
21517c4ee5bcSRichard Henderson                     top = p;
21527c4ee5bcSRichard Henderson                     remaining = TARGET_PAGE_SIZE;
21537c4ee5bcSRichard Henderson                 }
21547c4ee5bcSRichard Henderson             }
21557c4ee5bcSRichard Henderson         }
21567c4ee5bcSRichard Henderson         if (p != top) {
21577c4ee5bcSRichard Henderson             memcpy_to_target(top, scratch, p - top);
21587c4ee5bcSRichard Henderson         }
21597c4ee5bcSRichard Henderson     }
216059baae9aSStefan Brüns 
216131e31b8aSbellard     return p;
216231e31b8aSbellard }
216331e31b8aSbellard 
216459baae9aSStefan Brüns /* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of
216559baae9aSStefan Brüns  * argument/environment space. Newer kernels (>2.6.33) allow more,
216659baae9aSStefan Brüns  * dependent on stack size, but guarantee at least 32 pages for
216759baae9aSStefan Brüns  * backwards compatibility.
216859baae9aSStefan Brüns  */
216959baae9aSStefan Brüns #define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE)
217059baae9aSStefan Brüns 
217159baae9aSStefan Brüns static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
217231e31b8aSbellard                                  struct image_info *info)
217331e31b8aSbellard {
217459baae9aSStefan Brüns     abi_ulong size, error, guard;
2175872f3d04SRichard Henderson     int prot;
217631e31b8aSbellard 
2177703e0e89SRichard Henderson     size = guest_stack_size;
217859baae9aSStefan Brüns     if (size < STACK_LOWER_LIMIT) {
217959baae9aSStefan Brüns         size = STACK_LOWER_LIMIT;
218060dcbcb5SRichard Henderson     }
2181f4388205SHelge Deller 
2182f4388205SHelge Deller     if (STACK_GROWS_DOWN) {
218360dcbcb5SRichard Henderson         guard = TARGET_PAGE_SIZE;
21848e3b0cbbSMarc-André Lureau         if (guard < qemu_real_host_page_size()) {
21858e3b0cbbSMarc-André Lureau             guard = qemu_real_host_page_size();
218660dcbcb5SRichard Henderson         }
2187f4388205SHelge Deller     } else {
2188f4388205SHelge Deller         /* no guard page for hppa target where stack grows upwards. */
2189f4388205SHelge Deller         guard = 0;
2190f4388205SHelge Deller     }
219160dcbcb5SRichard Henderson 
2192872f3d04SRichard Henderson     prot = PROT_READ | PROT_WRITE;
2193872f3d04SRichard Henderson     if (info->exec_stack) {
2194872f3d04SRichard Henderson         prot |= PROT_EXEC;
2195872f3d04SRichard Henderson     }
2196872f3d04SRichard Henderson     error = target_mmap(0, size + guard, prot,
219760dcbcb5SRichard Henderson                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
219809bfb054Sbellard     if (error == -1) {
219960dcbcb5SRichard Henderson         perror("mmap stack");
220031e31b8aSbellard         exit(-1);
220131e31b8aSbellard     }
220231e31b8aSbellard 
220360dcbcb5SRichard Henderson     /* We reserve one extra page at the top of the stack as guard.  */
22047c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
220560dcbcb5SRichard Henderson         target_mprotect(error, guard, PROT_NONE);
220660dcbcb5SRichard Henderson         info->stack_limit = error + guard;
220759baae9aSStefan Brüns         return info->stack_limit + size - sizeof(void *);
22087c4ee5bcSRichard Henderson     } else {
22097c4ee5bcSRichard Henderson         info->stack_limit = error + size;
22107c4ee5bcSRichard Henderson         return error;
22117c4ee5bcSRichard Henderson     }
221231e31b8aSbellard }
221331e31b8aSbellard 
22142d385be6SRichard Henderson /**
22152d385be6SRichard Henderson  * zero_bss:
22162d385be6SRichard Henderson  *
22172d385be6SRichard Henderson  * Map and zero the bss.  We need to explicitly zero any fractional pages
22182d385be6SRichard Henderson  * after the data section (i.e. bss).  Return false on mapping failure.
22192d385be6SRichard Henderson  */
22202d385be6SRichard Henderson static bool zero_bss(abi_ulong start_bss, abi_ulong end_bss, int prot)
222131e31b8aSbellard {
22222d385be6SRichard Henderson     abi_ulong align_bss;
2223cf129f3aSRichard Henderson 
22242d385be6SRichard Henderson     align_bss = TARGET_PAGE_ALIGN(start_bss);
22252d385be6SRichard Henderson     end_bss = TARGET_PAGE_ALIGN(end_bss);
2226cf129f3aSRichard Henderson 
22272d385be6SRichard Henderson     if (start_bss < align_bss) {
22282d385be6SRichard Henderson         int flags = page_get_flags(start_bss);
2229cf129f3aSRichard Henderson 
22302d385be6SRichard Henderson         if (!(flags & PAGE_VALID)) {
22312d385be6SRichard Henderson             /* Map the start of the bss. */
22322d385be6SRichard Henderson             align_bss -= TARGET_PAGE_SIZE;
22332d385be6SRichard Henderson         } else if (flags & PAGE_WRITE) {
22342d385be6SRichard Henderson             /* The page is already mapped writable. */
22352d385be6SRichard Henderson             memset(g2h_untagged(start_bss), 0, align_bss - start_bss);
22362d385be6SRichard Henderson         } else {
22372d385be6SRichard Henderson             /* Read-only zeros? */
22382d385be6SRichard Henderson             g_assert_not_reached();
223931e31b8aSbellard         }
2240f46e9a0bSTom Musta     }
2241cf129f3aSRichard Henderson 
22422d385be6SRichard Henderson     return align_bss >= end_bss ||
22432d385be6SRichard Henderson            target_mmap(align_bss, end_bss - align_bss, prot,
22442d385be6SRichard Henderson                        MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) != -1;
2245853d6f7aSbellard }
2246853d6f7aSbellard 
2247d2796be6SMax Filippov #if defined(TARGET_ARM)
2248cf58affeSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2249cf58affeSChristophe Lyon {
2250cf58affeSChristophe Lyon     return exec->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC;
2251cf58affeSChristophe Lyon }
2252d2796be6SMax Filippov #elif defined(TARGET_XTENSA)
2253d2796be6SMax Filippov static int elf_is_fdpic(struct elfhdr *exec)
2254d2796be6SMax Filippov {
2255d2796be6SMax Filippov     return exec->e_ident[EI_OSABI] == ELFOSABI_XTENSA_FDPIC;
2256d2796be6SMax Filippov }
2257cf58affeSChristophe Lyon #else
2258a99856cdSChristophe Lyon /* Default implementation, always false.  */
2259a99856cdSChristophe Lyon static int elf_is_fdpic(struct elfhdr *exec)
2260a99856cdSChristophe Lyon {
2261a99856cdSChristophe Lyon     return 0;
2262a99856cdSChristophe Lyon }
2263cf58affeSChristophe Lyon #endif
2264a99856cdSChristophe Lyon 
22651af02e83SMike Frysinger static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
22661af02e83SMike Frysinger {
22671af02e83SMike Frysinger     uint16_t n;
22681af02e83SMike Frysinger     struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
22691af02e83SMike Frysinger 
22701af02e83SMike Frysinger     /* elf32_fdpic_loadseg */
22711af02e83SMike Frysinger     n = info->nsegs;
22721af02e83SMike Frysinger     while (n--) {
22731af02e83SMike Frysinger         sp -= 12;
22741af02e83SMike Frysinger         put_user_u32(loadsegs[n].addr, sp+0);
22751af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_vaddr, sp+4);
22761af02e83SMike Frysinger         put_user_u32(loadsegs[n].p_memsz, sp+8);
22771af02e83SMike Frysinger     }
22781af02e83SMike Frysinger 
22791af02e83SMike Frysinger     /* elf32_fdpic_loadmap */
22801af02e83SMike Frysinger     sp -= 4;
22811af02e83SMike Frysinger     put_user_u16(0, sp+0); /* version */
22821af02e83SMike Frysinger     put_user_u16(info->nsegs, sp+2); /* nsegs */
22831af02e83SMike Frysinger 
22841af02e83SMike Frysinger     info->personality = PER_LINUX_FDPIC;
22851af02e83SMike Frysinger     info->loadmap_addr = sp;
22861af02e83SMike Frysinger 
22871af02e83SMike Frysinger     return sp;
22881af02e83SMike Frysinger }
22891af02e83SMike Frysinger 
2290992f48a0Sblueswir1 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
229131e31b8aSbellard                                    struct elfhdr *exec,
22928e62a717SRichard Henderson                                    struct image_info *info,
22938e62a717SRichard Henderson                                    struct image_info *interp_info)
229431e31b8aSbellard {
2295992f48a0Sblueswir1     abi_ulong sp;
22967c4ee5bcSRichard Henderson     abi_ulong u_argc, u_argv, u_envp, u_auxv;
229753a5960aSpbrook     int size;
229814322badSLaurent ALFONSI     int i;
229914322badSLaurent ALFONSI     abi_ulong u_rand_bytes;
230014322badSLaurent ALFONSI     uint8_t k_rand_bytes[16];
2301fcdc0ab4SJiaxun Yang     abi_ulong u_platform, u_base_platform;
2302fcdc0ab4SJiaxun Yang     const char *k_platform, *k_base_platform;
2303863cf0b7Sj_mayer     const int n = sizeof(elf_addr_t);
230431e31b8aSbellard 
230553a5960aSpbrook     sp = p;
23061af02e83SMike Frysinger 
23071af02e83SMike Frysinger     /* Needs to be before we load the env/argc/... */
23081af02e83SMike Frysinger     if (elf_is_fdpic(exec)) {
23091af02e83SMike Frysinger         /* Need 4 byte alignment for these structs */
23101af02e83SMike Frysinger         sp &= ~3;
23111af02e83SMike Frysinger         sp = loader_build_fdpic_loadmap(info, sp);
23121af02e83SMike Frysinger         info->other_info = interp_info;
23131af02e83SMike Frysinger         if (interp_info) {
23141af02e83SMike Frysinger             interp_info->other_info = info;
23151af02e83SMike Frysinger             sp = loader_build_fdpic_loadmap(interp_info, sp);
23163cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = interp_info->loadmap_addr;
23173cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = interp_info->pt_dynamic_addr;
23183cb10cfaSChristophe Lyon         } else {
23193cb10cfaSChristophe Lyon             info->interpreter_loadmap_addr = 0;
23203cb10cfaSChristophe Lyon             info->interpreter_pt_dynamic_addr = 0;
23211af02e83SMike Frysinger         }
23221af02e83SMike Frysinger     }
23231af02e83SMike Frysinger 
2324fcdc0ab4SJiaxun Yang     u_base_platform = 0;
2325fcdc0ab4SJiaxun Yang     k_base_platform = ELF_BASE_PLATFORM;
2326fcdc0ab4SJiaxun Yang     if (k_base_platform) {
2327fcdc0ab4SJiaxun Yang         size_t len = strlen(k_base_platform) + 1;
2328fcdc0ab4SJiaxun Yang         if (STACK_GROWS_DOWN) {
2329fcdc0ab4SJiaxun Yang             sp -= (len + n - 1) & ~(n - 1);
2330fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2331fcdc0ab4SJiaxun Yang             /* FIXME - check return value of memcpy_to_target() for failure */
2332fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2333fcdc0ab4SJiaxun Yang         } else {
2334fcdc0ab4SJiaxun Yang             memcpy_to_target(sp, k_base_platform, len);
2335fcdc0ab4SJiaxun Yang             u_base_platform = sp;
2336fcdc0ab4SJiaxun Yang             sp += len + 1;
2337fcdc0ab4SJiaxun Yang         }
2338fcdc0ab4SJiaxun Yang     }
2339fcdc0ab4SJiaxun Yang 
234053a5960aSpbrook     u_platform = 0;
234115338fd7Sbellard     k_platform = ELF_PLATFORM;
234215338fd7Sbellard     if (k_platform) {
234315338fd7Sbellard         size_t len = strlen(k_platform) + 1;
23447c4ee5bcSRichard Henderson         if (STACK_GROWS_DOWN) {
234553a5960aSpbrook             sp -= (len + n - 1) & ~(n - 1);
234653a5960aSpbrook             u_platform = sp;
2347579a97f7Sbellard             /* FIXME - check return value of memcpy_to_target() for failure */
234853a5960aSpbrook             memcpy_to_target(sp, k_platform, len);
23497c4ee5bcSRichard Henderson         } else {
23507c4ee5bcSRichard Henderson             memcpy_to_target(sp, k_platform, len);
23517c4ee5bcSRichard Henderson             u_platform = sp;
23527c4ee5bcSRichard Henderson             sp += len + 1;
23537c4ee5bcSRichard Henderson         }
23547c4ee5bcSRichard Henderson     }
23557c4ee5bcSRichard Henderson 
23567c4ee5bcSRichard Henderson     /* Provide 16 byte alignment for the PRNG, and basic alignment for
23577c4ee5bcSRichard Henderson      * the argv and envp pointers.
23587c4ee5bcSRichard Henderson      */
23597c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
23607c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_DOWN(sp, 16);
23617c4ee5bcSRichard Henderson     } else {
23627c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp, 16);
236315338fd7Sbellard     }
236414322badSLaurent ALFONSI 
236514322badSLaurent ALFONSI     /*
2366c6a2377fSRichard Henderson      * Generate 16 random bytes for userspace PRNG seeding.
236714322badSLaurent ALFONSI      */
2368c6a2377fSRichard Henderson     qemu_guest_getrandom_nofail(k_rand_bytes, sizeof(k_rand_bytes));
23697c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
237014322badSLaurent ALFONSI         sp -= 16;
237114322badSLaurent ALFONSI         u_rand_bytes = sp;
237214322badSLaurent ALFONSI         /* FIXME - check return value of memcpy_to_target() for failure */
237314322badSLaurent ALFONSI         memcpy_to_target(sp, k_rand_bytes, 16);
23747c4ee5bcSRichard Henderson     } else {
23757c4ee5bcSRichard Henderson         memcpy_to_target(sp, k_rand_bytes, 16);
23767c4ee5bcSRichard Henderson         u_rand_bytes = sp;
23777c4ee5bcSRichard Henderson         sp += 16;
23787c4ee5bcSRichard Henderson     }
237914322badSLaurent ALFONSI 
238053a5960aSpbrook     size = (DLINFO_ITEMS + 1) * 2;
2381fcdc0ab4SJiaxun Yang     if (k_base_platform)
2382fcdc0ab4SJiaxun Yang         size += 2;
238315338fd7Sbellard     if (k_platform)
238453a5960aSpbrook         size += 2;
2385f5155289Sbellard #ifdef DLINFO_ARCH_ITEMS
238653a5960aSpbrook     size += DLINFO_ARCH_ITEMS * 2;
2387f5155289Sbellard #endif
2388ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2389ad6919dcSPeter Maydell     size += 2;
2390ad6919dcSPeter Maydell #endif
2391f516511eSPeter Maydell     info->auxv_len = size * n;
2392f516511eSPeter Maydell 
239353a5960aSpbrook     size += envc + argc + 2;
2394b9329d4bSRichard Henderson     size += 1;  /* argc itself */
239553a5960aSpbrook     size *= n;
23967c4ee5bcSRichard Henderson 
23977c4ee5bcSRichard Henderson     /* Allocate space and finalize stack alignment for entry now.  */
23987c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
23997c4ee5bcSRichard Henderson         u_argc = QEMU_ALIGN_DOWN(sp - size, STACK_ALIGNMENT);
24007c4ee5bcSRichard Henderson         sp = u_argc;
24017c4ee5bcSRichard Henderson     } else {
24027c4ee5bcSRichard Henderson         u_argc = sp;
24037c4ee5bcSRichard Henderson         sp = QEMU_ALIGN_UP(sp + size, STACK_ALIGNMENT);
24047c4ee5bcSRichard Henderson     }
24057c4ee5bcSRichard Henderson 
24067c4ee5bcSRichard Henderson     u_argv = u_argc + n;
24077c4ee5bcSRichard Henderson     u_envp = u_argv + (argc + 1) * n;
24087c4ee5bcSRichard Henderson     u_auxv = u_envp + (envc + 1) * n;
24097c4ee5bcSRichard Henderson     info->saved_auxv = u_auxv;
241060f1c801SRichard Henderson     info->argc = argc;
241160f1c801SRichard Henderson     info->envc = envc;
241260f1c801SRichard Henderson     info->argv = u_argv;
241360f1c801SRichard Henderson     info->envp = u_envp;
2414f5155289Sbellard 
2415863cf0b7Sj_mayer     /* This is correct because Linux defines
2416863cf0b7Sj_mayer      * elf_addr_t as Elf32_Off / Elf64_Off
2417863cf0b7Sj_mayer      */
241853a5960aSpbrook #define NEW_AUX_ENT(id, val) do {               \
24197c4ee5bcSRichard Henderson         put_user_ual(id, u_auxv);  u_auxv += n; \
24207c4ee5bcSRichard Henderson         put_user_ual(val, u_auxv); u_auxv += n; \
242153a5960aSpbrook     } while(0)
24222f619698Sbellard 
242382991bedSPeter Maydell #ifdef ARCH_DLINFO
242482991bedSPeter Maydell     /*
242582991bedSPeter Maydell      * ARCH_DLINFO must come first so platform specific code can enforce
242682991bedSPeter Maydell      * special alignment requirements on the AUXV if necessary (eg. PPC).
242782991bedSPeter Maydell      */
242882991bedSPeter Maydell     ARCH_DLINFO;
242982991bedSPeter Maydell #endif
2430f516511eSPeter Maydell     /* There must be exactly DLINFO_ITEMS entries here, or the assert
2431f516511eSPeter Maydell      * on info->auxv_len will trigger.
2432f516511eSPeter Maydell      */
24338e62a717SRichard Henderson     NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
2434992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
2435992f48a0Sblueswir1     NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
243633143c44SLaurent Vivier     if ((info->alignment & ~qemu_host_page_mask) != 0) {
243733143c44SLaurent Vivier         /* Target doesn't support host page size alignment */
243833143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
243933143c44SLaurent Vivier     } else {
244033143c44SLaurent Vivier         NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(MAX(TARGET_PAGE_SIZE,
244133143c44SLaurent Vivier                                                qemu_host_page_size)));
244233143c44SLaurent Vivier     }
24438e62a717SRichard Henderson     NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
2444992f48a0Sblueswir1     NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
24458e62a717SRichard Henderson     NEW_AUX_ENT(AT_ENTRY, info->entry);
2446992f48a0Sblueswir1     NEW_AUX_ENT(AT_UID, (abi_ulong) getuid());
2447992f48a0Sblueswir1     NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid());
2448992f48a0Sblueswir1     NEW_AUX_ENT(AT_GID, (abi_ulong) getgid());
2449992f48a0Sblueswir1     NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
2450992f48a0Sblueswir1     NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
2451a07c67dfSpbrook     NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
245214322badSLaurent ALFONSI     NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
2453444cd5c3SMarco A L Barbosa     NEW_AUX_ENT(AT_SECURE, (abi_ulong) qemu_getauxval(AT_SECURE));
2454e0d1673dSLirong Yuan     NEW_AUX_ENT(AT_EXECFN, info->file_string);
245514322badSLaurent ALFONSI 
2456ad6919dcSPeter Maydell #ifdef ELF_HWCAP2
2457ad6919dcSPeter Maydell     NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
2458ad6919dcSPeter Maydell #endif
2459ad6919dcSPeter Maydell 
2460fcdc0ab4SJiaxun Yang     if (u_base_platform) {
2461fcdc0ab4SJiaxun Yang         NEW_AUX_ENT(AT_BASE_PLATFORM, u_base_platform);
2462fcdc0ab4SJiaxun Yang     }
24637c4ee5bcSRichard Henderson     if (u_platform) {
246453a5960aSpbrook         NEW_AUX_ENT(AT_PLATFORM, u_platform);
24657c4ee5bcSRichard Henderson     }
24667c4ee5bcSRichard Henderson     NEW_AUX_ENT (AT_NULL, 0);
2467f5155289Sbellard #undef NEW_AUX_ENT
2468f5155289Sbellard 
2469f516511eSPeter Maydell     /* Check that our initial calculation of the auxv length matches how much
2470f516511eSPeter Maydell      * we actually put into it.
2471f516511eSPeter Maydell      */
2472f516511eSPeter Maydell     assert(info->auxv_len == u_auxv - info->saved_auxv);
2473edf8e2afSMika Westerberg 
24747c4ee5bcSRichard Henderson     put_user_ual(argc, u_argc);
24757c4ee5bcSRichard Henderson 
24767c4ee5bcSRichard Henderson     p = info->arg_strings;
24777c4ee5bcSRichard Henderson     for (i = 0; i < argc; ++i) {
24787c4ee5bcSRichard Henderson         put_user_ual(p, u_argv);
24797c4ee5bcSRichard Henderson         u_argv += n;
24807c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
24817c4ee5bcSRichard Henderson     }
24827c4ee5bcSRichard Henderson     put_user_ual(0, u_argv);
24837c4ee5bcSRichard Henderson 
24847c4ee5bcSRichard Henderson     p = info->env_strings;
24857c4ee5bcSRichard Henderson     for (i = 0; i < envc; ++i) {
24867c4ee5bcSRichard Henderson         put_user_ual(p, u_envp);
24877c4ee5bcSRichard Henderson         u_envp += n;
24887c4ee5bcSRichard Henderson         p += target_strlen(p) + 1;
24897c4ee5bcSRichard Henderson     }
24907c4ee5bcSRichard Henderson     put_user_ual(0, u_envp);
24917c4ee5bcSRichard Henderson 
249231e31b8aSbellard     return sp;
249331e31b8aSbellard }
249431e31b8aSbellard 
2495f5ef0e51SRichard Henderson #if defined(HI_COMMPAGE)
2496eee816c0SRichard Henderson #define LO_COMMPAGE -1
2497f5ef0e51SRichard Henderson #elif defined(LO_COMMPAGE)
249866346fafSRichard Henderson #define HI_COMMPAGE 0
2499f5ef0e51SRichard Henderson #else
2500f5ef0e51SRichard Henderson #define HI_COMMPAGE 0
2501eee816c0SRichard Henderson #define LO_COMMPAGE -1
2502d461b73eSRichard Henderson #ifndef INIT_GUEST_COMMPAGE
2503ee947430SAlex Bennée #define init_guest_commpage() true
2504ee947430SAlex Bennée #endif
2505d461b73eSRichard Henderson #endif
2506ee947430SAlex Bennée 
2507ee947430SAlex Bennée static void pgb_fail_in_use(const char *image_name)
2508ee947430SAlex Bennée {
2509ee947430SAlex Bennée     error_report("%s: requires virtual address space that is in use "
2510ee947430SAlex Bennée                  "(omit the -B option or choose a different value)",
2511ee947430SAlex Bennée                  image_name);
2512ee947430SAlex Bennée     exit(EXIT_FAILURE);
2513ee947430SAlex Bennée }
2514ee947430SAlex Bennée 
2515ee947430SAlex Bennée static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr,
2516ee947430SAlex Bennée                                 abi_ulong guest_hiaddr, long align)
2517ee947430SAlex Bennée {
2518ee947430SAlex Bennée     const int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
2519ee947430SAlex Bennée     void *addr, *test;
2520ee947430SAlex Bennée 
2521ee947430SAlex Bennée     if (!QEMU_IS_ALIGNED(guest_base, align)) {
25225ca870b9SRichard Henderson         fprintf(stderr, "Requested guest base %p does not satisfy "
2523ee947430SAlex Bennée                 "host minimum alignment (0x%lx)\n",
25245ca870b9SRichard Henderson                 (void *)guest_base, align);
2525ee947430SAlex Bennée         exit(EXIT_FAILURE);
2526ee947430SAlex Bennée     }
2527ee947430SAlex Bennée 
2528ee947430SAlex Bennée     /*
2529ee947430SAlex Bennée      * Expand the allocation to the entire reserved_va.
2530ee947430SAlex Bennée      * Exclude the mmap_min_addr hole.
2531ee947430SAlex Bennée      */
2532ee947430SAlex Bennée     if (reserved_va) {
2533ee947430SAlex Bennée         guest_loaddr = (guest_base >= mmap_min_addr ? 0
2534ee947430SAlex Bennée                         : mmap_min_addr - guest_base);
253595059f9cSRichard Henderson         guest_hiaddr = reserved_va;
2536ee947430SAlex Bennée     }
2537ee947430SAlex Bennée 
2538ee947430SAlex Bennée     /* Reserve the address space for the binary, or reserved_va. */
25393e8f1628SRichard Henderson     test = g2h_untagged(guest_loaddr);
2540a3a67f54SRichard Henderson     addr = mmap(test, guest_hiaddr - guest_loaddr + 1, PROT_NONE, flags, -1, 0);
2541ee947430SAlex Bennée     if (test != addr) {
2542ee947430SAlex Bennée         pgb_fail_in_use(image_name);
2543ee947430SAlex Bennée     }
2544ee947430SAlex Bennée }
2545ee947430SAlex Bennée 
2546ad592e37SAlex Bennée /**
2547ad592e37SAlex Bennée  * pgd_find_hole_fallback: potential mmap address
2548ad592e37SAlex Bennée  * @guest_size: size of available space
2549ad592e37SAlex Bennée  * @brk: location of break
2550ad592e37SAlex Bennée  * @align: memory alignment
2551ad592e37SAlex Bennée  *
2552ad592e37SAlex Bennée  * This is a fallback method for finding a hole in the host address
2553ad592e37SAlex Bennée  * space if we don't have the benefit of being able to access
2554ad592e37SAlex Bennée  * /proc/self/map. It can potentially take a very long time as we can
2555ad592e37SAlex Bennée  * only dumbly iterate up the host address space seeing if the
2556ad592e37SAlex Bennée  * allocation would work.
2557ad592e37SAlex Bennée  */
25585c3e87f3SAlex Bennée static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk,
25595c3e87f3SAlex Bennée                                         long align, uintptr_t offset)
2560ad592e37SAlex Bennée {
2561ad592e37SAlex Bennée     uintptr_t base;
2562ad592e37SAlex Bennée 
2563ad592e37SAlex Bennée     /* Start (aligned) at the bottom and work our way up */
2564ad592e37SAlex Bennée     base = ROUND_UP(mmap_min_addr, align);
2565ad592e37SAlex Bennée 
2566ad592e37SAlex Bennée     while (true) {
2567ad592e37SAlex Bennée         uintptr_t align_start, end;
2568ad592e37SAlex Bennée         align_start = ROUND_UP(base, align);
25695c3e87f3SAlex Bennée         end = align_start + guest_size + offset;
2570ad592e37SAlex Bennée 
2571ad592e37SAlex Bennée         /* if brk is anywhere in the range give ourselves some room to grow. */
2572ad592e37SAlex Bennée         if (align_start <= brk && brk < end) {
2573ad592e37SAlex Bennée             base = brk + (16 * MiB);
2574ad592e37SAlex Bennée             continue;
2575ad592e37SAlex Bennée         } else if (align_start + guest_size < align_start) {
2576ad592e37SAlex Bennée             /* we have run out of space */
2577ad592e37SAlex Bennée             return -1;
2578ad592e37SAlex Bennée         } else {
25792667e069SAlex Bennée             int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE |
25802667e069SAlex Bennée                 MAP_FIXED_NOREPLACE;
2581ad592e37SAlex Bennée             void * mmap_start = mmap((void *) align_start, guest_size,
2582ad592e37SAlex Bennée                                      PROT_NONE, flags, -1, 0);
2583ad592e37SAlex Bennée             if (mmap_start != MAP_FAILED) {
25847e588fbcSVincent Fazio                 munmap(mmap_start, guest_size);
2585934eed51SVincent Fazio                 if (mmap_start == (void *) align_start) {
25865c3e87f3SAlex Bennée                     return (uintptr_t) mmap_start + offset;
2587ad592e37SAlex Bennée                 }
25882667e069SAlex Bennée             }
2589ad592e37SAlex Bennée             base += qemu_host_page_size;
2590ad592e37SAlex Bennée         }
2591ad592e37SAlex Bennée     }
2592ad592e37SAlex Bennée }
2593ad592e37SAlex Bennée 
2594ee947430SAlex Bennée /* Return value for guest_base, or -1 if no hole found. */
2595ee947430SAlex Bennée static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size,
25965c3e87f3SAlex Bennée                                long align, uintptr_t offset)
2597ee947430SAlex Bennée {
25983ce3dd8cSRichard Henderson     IntervalTreeRoot *maps;
25993ce3dd8cSRichard Henderson     IntervalTreeNode *iter;
2600ee947430SAlex Bennée     uintptr_t this_start, this_end, next_start, brk;
2601ee947430SAlex Bennée     intptr_t ret = -1;
2602ee947430SAlex Bennée 
2603ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_loaddr, align));
2604ee947430SAlex Bennée 
2605ee947430SAlex Bennée     maps = read_self_maps();
2606ee947430SAlex Bennée 
2607ee947430SAlex Bennée     /* Read brk after we've read the maps, which will malloc. */
2608ee947430SAlex Bennée     brk = (uintptr_t)sbrk(0);
2609ee947430SAlex Bennée 
2610ad592e37SAlex Bennée     if (!maps) {
2611190674f3SAlex Bennée         return pgd_find_hole_fallback(guest_size, brk, align, offset);
2612ad592e37SAlex Bennée     }
2613ad592e37SAlex Bennée 
2614ee947430SAlex Bennée     /* The first hole is before the first map entry. */
2615ee947430SAlex Bennée     this_start = mmap_min_addr;
2616ee947430SAlex Bennée 
26173ce3dd8cSRichard Henderson     for (iter = interval_tree_iter_first(maps, 0, -1);
26183ce3dd8cSRichard Henderson          iter;
26193ce3dd8cSRichard Henderson          this_start = next_start,
26203ce3dd8cSRichard Henderson          iter = interval_tree_iter_next(iter, 0, -1)) {
26213ce3dd8cSRichard Henderson         MapInfo *info = container_of(iter, MapInfo, itree);
2622ee947430SAlex Bennée         uintptr_t align_start, hole_size;
2623ee947430SAlex Bennée 
26243ce3dd8cSRichard Henderson         this_end = info->itree.start;
26253ce3dd8cSRichard Henderson         next_start = info->itree.last + 1;
26265c3e87f3SAlex Bennée         align_start = ROUND_UP(this_start + offset, align);
2627ee947430SAlex Bennée 
2628ee947430SAlex Bennée         /* Skip holes that are too small. */
2629ee947430SAlex Bennée         if (align_start >= this_end) {
2630ee947430SAlex Bennée             continue;
2631ee947430SAlex Bennée         }
2632ee947430SAlex Bennée         hole_size = this_end - align_start;
2633ee947430SAlex Bennée         if (hole_size < guest_size) {
2634ee947430SAlex Bennée             continue;
2635ee947430SAlex Bennée         }
2636ee947430SAlex Bennée 
2637ee947430SAlex Bennée         /* If this hole contains brk, give ourselves some room to grow. */
2638ee947430SAlex Bennée         if (this_start <= brk && brk < this_end) {
2639ee947430SAlex Bennée             hole_size -= guest_size;
2640ee947430SAlex Bennée             if (sizeof(uintptr_t) == 8 && hole_size >= 1 * GiB) {
2641ee947430SAlex Bennée                 align_start += 1 * GiB;
2642ee947430SAlex Bennée             } else if (hole_size >= 16 * MiB) {
2643ee947430SAlex Bennée                 align_start += 16 * MiB;
2644ee947430SAlex Bennée             } else {
2645ee947430SAlex Bennée                 align_start = (this_end - guest_size) & -align;
2646ee947430SAlex Bennée                 if (align_start < this_start) {
2647ee947430SAlex Bennée                     continue;
2648ee947430SAlex Bennée                 }
2649ee947430SAlex Bennée             }
2650ee947430SAlex Bennée         }
2651ee947430SAlex Bennée 
2652ee947430SAlex Bennée         /* Record the lowest successful match. */
2653ee947430SAlex Bennée         if (ret < 0) {
2654190674f3SAlex Bennée             ret = align_start;
2655ee947430SAlex Bennée         }
2656ee947430SAlex Bennée         /* If this hole contains the identity map, select it. */
2657ee947430SAlex Bennée         if (align_start <= guest_loaddr &&
2658ee947430SAlex Bennée             guest_loaddr + guest_size <= this_end) {
2659ee947430SAlex Bennée             ret = 0;
2660ee947430SAlex Bennée         }
2661ee947430SAlex Bennée         /* If this hole ends above the identity map, stop looking. */
2662ee947430SAlex Bennée         if (this_end >= guest_loaddr) {
2663ee947430SAlex Bennée             break;
2664ee947430SAlex Bennée         }
2665ee947430SAlex Bennée     }
2666ee947430SAlex Bennée     free_self_maps(maps);
2667ee947430SAlex Bennée     return ret;
2668ee947430SAlex Bennée }
2669ee947430SAlex Bennée 
2670ee947430SAlex Bennée static void pgb_static(const char *image_name, abi_ulong orig_loaddr,
2671ee947430SAlex Bennée                        abi_ulong orig_hiaddr, long align)
2672ee947430SAlex Bennée {
2673ee947430SAlex Bennée     uintptr_t loaddr = orig_loaddr;
2674ee947430SAlex Bennée     uintptr_t hiaddr = orig_hiaddr;
26755c3e87f3SAlex Bennée     uintptr_t offset = 0;
2676ee947430SAlex Bennée     uintptr_t addr;
2677ee947430SAlex Bennée 
2678ee947430SAlex Bennée     loaddr &= -align;
267966346fafSRichard Henderson     if (HI_COMMPAGE) {
2680ee947430SAlex Bennée         /*
2681ee947430SAlex Bennée          * Extend the allocation to include the commpage.
26825c3e87f3SAlex Bennée          * For a 64-bit host, this is just 4GiB; for a 32-bit host we
26835c3e87f3SAlex Bennée          * need to ensure there is space bellow the guest_base so we
26845c3e87f3SAlex Bennée          * can map the commpage in the place needed when the address
26855c3e87f3SAlex Bennée          * arithmetic wraps around.
2686ee947430SAlex Bennée          */
2687ee947430SAlex Bennée         if (sizeof(uintptr_t) == 8 || loaddr >= 0x80000000u) {
2688a3a67f54SRichard Henderson             hiaddr = UINT32_MAX;
2689ee947430SAlex Bennée         } else {
269066346fafSRichard Henderson             offset = -(HI_COMMPAGE & -align);
2691ee947430SAlex Bennée         }
2692eee816c0SRichard Henderson     } else if (LO_COMMPAGE != -1) {
2693f5ef0e51SRichard Henderson         loaddr = MIN(loaddr, LO_COMMPAGE & -align);
2694ee947430SAlex Bennée     }
2695ee947430SAlex Bennée 
2696a3a67f54SRichard Henderson     addr = pgb_find_hole(loaddr, hiaddr - loaddr + 1, align, offset);
2697ee947430SAlex Bennée     if (addr == -1) {
2698ee947430SAlex Bennée         /*
269966346fafSRichard Henderson          * If HI_COMMPAGE, there *might* be a non-consecutive allocation
2700ee947430SAlex Bennée          * that can satisfy both.  But as the normal arm32 link base address
2701ee947430SAlex Bennée          * is ~32k, and we extend down to include the commpage, making the
2702ee947430SAlex Bennée          * overhead only ~96k, this is unlikely.
2703ee947430SAlex Bennée          */
2704ee947430SAlex Bennée         error_report("%s: Unable to allocate %#zx bytes of "
2705ee947430SAlex Bennée                      "virtual address space", image_name,
2706ee947430SAlex Bennée                      (size_t)(hiaddr - loaddr));
2707ee947430SAlex Bennée         exit(EXIT_FAILURE);
2708ee947430SAlex Bennée     }
2709ee947430SAlex Bennée 
2710ee947430SAlex Bennée     guest_base = addr;
2711ee947430SAlex Bennée }
2712ee947430SAlex Bennée 
2713ee947430SAlex Bennée static void pgb_dynamic(const char *image_name, long align)
2714ee947430SAlex Bennée {
2715ee947430SAlex Bennée     /*
2716ee947430SAlex Bennée      * The executable is dynamic and does not require a fixed address.
2717ee947430SAlex Bennée      * All we need is a commpage that satisfies align.
2718ee947430SAlex Bennée      * If we do not need a commpage, leave guest_base == 0.
2719ee947430SAlex Bennée      */
272066346fafSRichard Henderson     if (HI_COMMPAGE) {
2721ee947430SAlex Bennée         uintptr_t addr, commpage;
2722ee947430SAlex Bennée 
2723ee947430SAlex Bennée         /* 64-bit hosts should have used reserved_va. */
2724ee947430SAlex Bennée         assert(sizeof(uintptr_t) == 4);
2725ee947430SAlex Bennée 
2726ee947430SAlex Bennée         /*
2727ee947430SAlex Bennée          * By putting the commpage at the first hole, that puts guest_base
2728ee947430SAlex Bennée          * just above that, and maximises the positive guest addresses.
2729ee947430SAlex Bennée          */
273066346fafSRichard Henderson         commpage = HI_COMMPAGE & -align;
27315c3e87f3SAlex Bennée         addr = pgb_find_hole(commpage, -commpage, align, 0);
2732ee947430SAlex Bennée         assert(addr != -1);
2733ee947430SAlex Bennée         guest_base = addr;
2734ee947430SAlex Bennée     }
2735ee947430SAlex Bennée }
2736ee947430SAlex Bennée 
2737ee947430SAlex Bennée static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr,
2738ee947430SAlex Bennée                             abi_ulong guest_hiaddr, long align)
2739ee947430SAlex Bennée {
2740c1f6ad79SAlex Bennée     int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
2741ee947430SAlex Bennée     void *addr, *test;
2742ee947430SAlex Bennée 
2743ee947430SAlex Bennée     /* Widen the "image" to the entire reserved address space. */
2744ee947430SAlex Bennée     pgb_static(image_name, 0, reserved_va, align);
2745ee947430SAlex Bennée 
27462667e069SAlex Bennée     /* osdep.h defines this as 0 if it's missing */
2747c1f6ad79SAlex Bennée     flags |= MAP_FIXED_NOREPLACE;
2748c1f6ad79SAlex Bennée 
2749ee947430SAlex Bennée     /* Reserve the memory on the host. */
2750ee947430SAlex Bennée     assert(guest_base != 0);
27513e8f1628SRichard Henderson     test = g2h_untagged(0);
275295059f9cSRichard Henderson     addr = mmap(test, reserved_va + 1, PROT_NONE, flags, -1, 0);
2753fb730c86SAlex Bennée     if (addr == MAP_FAILED || addr != test) {
2754ee947430SAlex Bennée         error_report("Unable to reserve 0x%lx bytes of virtual address "
2755fb730c86SAlex Bennée                      "space at %p (%s) for use as guest address space (check your "
2756f101c25cSAndrew Jeffery                      "virtual memory ulimit setting, mmap_min_addr or reserve less "
2757e9289071SAndrew Jeffery                      "using qemu-user's -R option)",
2758e9289071SAndrew Jeffery                      reserved_va + 1, test, strerror(errno));
2759ee947430SAlex Bennée         exit(EXIT_FAILURE);
2760ee947430SAlex Bennée     }
2761ee947430SAlex Bennée }
2762ee947430SAlex Bennée 
2763ee947430SAlex Bennée void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
2764ee947430SAlex Bennée                       abi_ulong guest_hiaddr)
2765dce10401SMeador Inge {
276630ab9ef2SRichard Henderson     /* In order to use host shmat, we must be able to honor SHMLBA.  */
2767ee947430SAlex Bennée     uintptr_t align = MAX(SHMLBA, qemu_host_page_size);
2768dce10401SMeador Inge 
2769*0c441aebSRichard Henderson     /* Sanity check the guest binary. */
2770*0c441aebSRichard Henderson     if (reserved_va) {
2771*0c441aebSRichard Henderson         if (guest_hiaddr > reserved_va) {
2772*0c441aebSRichard Henderson             error_report("%s: requires more than reserved virtual "
2773*0c441aebSRichard Henderson                          "address space (0x%" PRIx64 " > 0x%lx)",
2774*0c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr, reserved_va);
2775*0c441aebSRichard Henderson             exit(EXIT_FAILURE);
2776*0c441aebSRichard Henderson         }
2777*0c441aebSRichard Henderson     } else {
2778*0c441aebSRichard Henderson         if (guest_hiaddr != (uintptr_t)guest_hiaddr) {
2779*0c441aebSRichard Henderson             error_report("%s: requires more virtual address space "
2780*0c441aebSRichard Henderson                          "than the host can provide (0x%" PRIx64 ")",
2781*0c441aebSRichard Henderson                          image_name, (uint64_t)guest_hiaddr + 1);
2782*0c441aebSRichard Henderson             exit(EXIT_FAILURE);
2783*0c441aebSRichard Henderson         }
2784*0c441aebSRichard Henderson     }
2785*0c441aebSRichard Henderson 
2786ee947430SAlex Bennée     if (have_guest_base) {
2787ee947430SAlex Bennée         pgb_have_guest_base(image_name, guest_loaddr, guest_hiaddr, align);
2788ee947430SAlex Bennée     } else if (reserved_va) {
2789ee947430SAlex Bennée         pgb_reserved_va(image_name, guest_loaddr, guest_hiaddr, align);
2790ee947430SAlex Bennée     } else if (guest_loaddr) {
2791ee947430SAlex Bennée         pgb_static(image_name, guest_loaddr, guest_hiaddr, align);
2792293f2060SLuke Shumaker     } else {
2793ee947430SAlex Bennée         pgb_dynamic(image_name, align);
2794806d1021SMeador Inge     }
2795806d1021SMeador Inge 
2796ee947430SAlex Bennée     /* Reserve and initialize the commpage. */
2797ee947430SAlex Bennée     if (!init_guest_commpage()) {
2798ee947430SAlex Bennée         /*
2799ee947430SAlex Bennée          * With have_guest_base, the user has selected the address and
2800ee947430SAlex Bennée          * we are trying to work with that.  Otherwise, we have selected
2801ee947430SAlex Bennée          * free space and init_guest_commpage must succeeded.
28027ad75eeaSLuke Shumaker          */
2803ee947430SAlex Bennée         assert(have_guest_base);
2804ee947430SAlex Bennée         pgb_fail_in_use(image_name);
2805dce10401SMeador Inge     }
2806dce10401SMeador Inge 
2807ee947430SAlex Bennée     assert(QEMU_IS_ALIGNED(guest_base, align));
2808ee947430SAlex Bennée     qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space "
2809ee947430SAlex Bennée                   "@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
2810dce10401SMeador Inge }
2811dce10401SMeador Inge 
281283f990ebSRichard Henderson enum {
281383f990ebSRichard Henderson     /* The string "GNU\0" as a magic number. */
281483f990ebSRichard Henderson     GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
281583f990ebSRichard Henderson     NOTE_DATA_SZ = 1 * KiB,
281683f990ebSRichard Henderson     NOTE_NAME_SZ = 4,
281783f990ebSRichard Henderson     ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
281883f990ebSRichard Henderson };
281983f990ebSRichard Henderson 
282083f990ebSRichard Henderson /*
282183f990ebSRichard Henderson  * Process a single gnu_property entry.
282283f990ebSRichard Henderson  * Return false for error.
282383f990ebSRichard Henderson  */
282483f990ebSRichard Henderson static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
282583f990ebSRichard Henderson                                struct image_info *info, bool have_prev_type,
282683f990ebSRichard Henderson                                uint32_t *prev_type, Error **errp)
282783f990ebSRichard Henderson {
282883f990ebSRichard Henderson     uint32_t pr_type, pr_datasz, step;
282983f990ebSRichard Henderson 
283083f990ebSRichard Henderson     if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
283183f990ebSRichard Henderson         goto error_data;
283283f990ebSRichard Henderson     }
283383f990ebSRichard Henderson     datasz -= *off;
283483f990ebSRichard Henderson     data += *off / sizeof(uint32_t);
283583f990ebSRichard Henderson 
283683f990ebSRichard Henderson     if (datasz < 2 * sizeof(uint32_t)) {
283783f990ebSRichard Henderson         goto error_data;
283883f990ebSRichard Henderson     }
283983f990ebSRichard Henderson     pr_type = data[0];
284083f990ebSRichard Henderson     pr_datasz = data[1];
284183f990ebSRichard Henderson     data += 2;
284283f990ebSRichard Henderson     datasz -= 2 * sizeof(uint32_t);
284383f990ebSRichard Henderson     step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
284483f990ebSRichard Henderson     if (step > datasz) {
284583f990ebSRichard Henderson         goto error_data;
284683f990ebSRichard Henderson     }
284783f990ebSRichard Henderson 
284883f990ebSRichard Henderson     /* Properties are supposed to be unique and sorted on pr_type. */
284983f990ebSRichard Henderson     if (have_prev_type && pr_type <= *prev_type) {
285083f990ebSRichard Henderson         if (pr_type == *prev_type) {
285183f990ebSRichard Henderson             error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
285283f990ebSRichard Henderson         } else {
285383f990ebSRichard Henderson             error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
285483f990ebSRichard Henderson         }
285583f990ebSRichard Henderson         return false;
285683f990ebSRichard Henderson     }
285783f990ebSRichard Henderson     *prev_type = pr_type;
285883f990ebSRichard Henderson 
285983f990ebSRichard Henderson     if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
286083f990ebSRichard Henderson         return false;
286183f990ebSRichard Henderson     }
286283f990ebSRichard Henderson 
286383f990ebSRichard Henderson     *off += 2 * sizeof(uint32_t) + step;
286483f990ebSRichard Henderson     return true;
286583f990ebSRichard Henderson 
286683f990ebSRichard Henderson  error_data:
286783f990ebSRichard Henderson     error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
286883f990ebSRichard Henderson     return false;
286983f990ebSRichard Henderson }
287083f990ebSRichard Henderson 
287183f990ebSRichard Henderson /* Process NT_GNU_PROPERTY_TYPE_0. */
287283f990ebSRichard Henderson static bool parse_elf_properties(int image_fd,
287383f990ebSRichard Henderson                                  struct image_info *info,
287483f990ebSRichard Henderson                                  const struct elf_phdr *phdr,
287583f990ebSRichard Henderson                                  char bprm_buf[BPRM_BUF_SIZE],
287683f990ebSRichard Henderson                                  Error **errp)
287783f990ebSRichard Henderson {
287883f990ebSRichard Henderson     union {
287983f990ebSRichard Henderson         struct elf_note nhdr;
288083f990ebSRichard Henderson         uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
288183f990ebSRichard Henderson     } note;
288283f990ebSRichard Henderson 
288383f990ebSRichard Henderson     int n, off, datasz;
288483f990ebSRichard Henderson     bool have_prev_type;
288583f990ebSRichard Henderson     uint32_t prev_type;
288683f990ebSRichard Henderson 
288783f990ebSRichard Henderson     /* Unless the arch requires properties, ignore them. */
288883f990ebSRichard Henderson     if (!ARCH_USE_GNU_PROPERTY) {
288983f990ebSRichard Henderson         return true;
289083f990ebSRichard Henderson     }
289183f990ebSRichard Henderson 
289283f990ebSRichard Henderson     /* If the properties are crazy large, that's too bad. */
289383f990ebSRichard Henderson     n = phdr->p_filesz;
289483f990ebSRichard Henderson     if (n > sizeof(note)) {
289583f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too large");
289683f990ebSRichard Henderson         return false;
289783f990ebSRichard Henderson     }
289883f990ebSRichard Henderson     if (n < sizeof(note.nhdr)) {
289983f990ebSRichard Henderson         error_setg(errp, "PT_GNU_PROPERTY too small");
290083f990ebSRichard Henderson         return false;
290183f990ebSRichard Henderson     }
290283f990ebSRichard Henderson 
290383f990ebSRichard Henderson     if (phdr->p_offset + n <= BPRM_BUF_SIZE) {
290483f990ebSRichard Henderson         memcpy(&note, bprm_buf + phdr->p_offset, n);
290583f990ebSRichard Henderson     } else {
290683f990ebSRichard Henderson         ssize_t len = pread(image_fd, &note, n, phdr->p_offset);
290783f990ebSRichard Henderson         if (len != n) {
290883f990ebSRichard Henderson             error_setg_errno(errp, errno, "Error reading file header");
290983f990ebSRichard Henderson             return false;
291083f990ebSRichard Henderson         }
291183f990ebSRichard Henderson     }
291283f990ebSRichard Henderson 
291383f990ebSRichard Henderson     /*
291483f990ebSRichard Henderson      * The contents of a valid PT_GNU_PROPERTY is a sequence
291583f990ebSRichard Henderson      * of uint32_t -- swap them all now.
291683f990ebSRichard Henderson      */
291783f990ebSRichard Henderson #ifdef BSWAP_NEEDED
291883f990ebSRichard Henderson     for (int i = 0; i < n / 4; i++) {
291983f990ebSRichard Henderson         bswap32s(note.data + i);
292083f990ebSRichard Henderson     }
292183f990ebSRichard Henderson #endif
292283f990ebSRichard Henderson 
292383f990ebSRichard Henderson     /*
292483f990ebSRichard Henderson      * Note that nhdr is 3 words, and that the "name" described by namesz
292583f990ebSRichard Henderson      * immediately follows nhdr and is thus at the 4th word.  Further, all
292683f990ebSRichard Henderson      * of the inputs to the kernel's round_up are multiples of 4.
292783f990ebSRichard Henderson      */
292883f990ebSRichard Henderson     if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
292983f990ebSRichard Henderson         note.nhdr.n_namesz != NOTE_NAME_SZ ||
293083f990ebSRichard Henderson         note.data[3] != GNU0_MAGIC) {
293183f990ebSRichard Henderson         error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
293283f990ebSRichard Henderson         return false;
293383f990ebSRichard Henderson     }
293483f990ebSRichard Henderson     off = sizeof(note.nhdr) + NOTE_NAME_SZ;
293583f990ebSRichard Henderson 
293683f990ebSRichard Henderson     datasz = note.nhdr.n_descsz + off;
293783f990ebSRichard Henderson     if (datasz > n) {
293883f990ebSRichard Henderson         error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
293983f990ebSRichard Henderson         return false;
294083f990ebSRichard Henderson     }
294183f990ebSRichard Henderson 
294283f990ebSRichard Henderson     have_prev_type = false;
294383f990ebSRichard Henderson     prev_type = 0;
294483f990ebSRichard Henderson     while (1) {
294583f990ebSRichard Henderson         if (off == datasz) {
294683f990ebSRichard Henderson             return true;  /* end, exit ok */
294783f990ebSRichard Henderson         }
294883f990ebSRichard Henderson         if (!parse_elf_property(note.data, &off, datasz, info,
294983f990ebSRichard Henderson                                 have_prev_type, &prev_type, errp)) {
295083f990ebSRichard Henderson             return false;
295183f990ebSRichard Henderson         }
295283f990ebSRichard Henderson         have_prev_type = true;
295383f990ebSRichard Henderson     }
295483f990ebSRichard Henderson }
295583f990ebSRichard Henderson 
29568e62a717SRichard Henderson /* Load an ELF image into the address space.
295731e31b8aSbellard 
29588e62a717SRichard Henderson    IMAGE_NAME is the filename of the image, to use in error messages.
29598e62a717SRichard Henderson    IMAGE_FD is the open file descriptor for the image.
29608e62a717SRichard Henderson 
29618e62a717SRichard Henderson    BPRM_BUF is a copy of the beginning of the file; this of course
29628e62a717SRichard Henderson    contains the elf file header at offset 0.  It is assumed that this
29638e62a717SRichard Henderson    buffer is sufficiently aligned to present no problems to the host
29648e62a717SRichard Henderson    in accessing data at aligned offsets within the buffer.
29658e62a717SRichard Henderson 
29668e62a717SRichard Henderson    On return: INFO values will be filled in, as necessary or available.  */
29678e62a717SRichard Henderson 
29688e62a717SRichard Henderson static void load_elf_image(const char *image_name, int image_fd,
2969bf858897SRichard Henderson                            struct image_info *info, char **pinterp_name,
29709955ffacSRichard Henderson                            char bprm_buf[BPRM_BUF_SIZE])
297131e31b8aSbellard {
29728e62a717SRichard Henderson     struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
29738e62a717SRichard Henderson     struct elf_phdr *phdr;
29748e62a717SRichard Henderson     abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
2975e8384b37SRichard Henderson     int i, retval, prot_exec;
2976c7f17e7bSRichard Henderson     Error *err = NULL;
297731e31b8aSbellard 
29788e62a717SRichard Henderson     /* First of all, some simple consistency checks */
29798e62a717SRichard Henderson     if (!elf_check_ident(ehdr)) {
2980c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
29818e62a717SRichard Henderson         goto exit_errmsg;
29828e62a717SRichard Henderson     }
29838e62a717SRichard Henderson     bswap_ehdr(ehdr);
29848e62a717SRichard Henderson     if (!elf_check_ehdr(ehdr)) {
2985c7f17e7bSRichard Henderson         error_setg(&err, "Invalid ELF image for this architecture");
29868e62a717SRichard Henderson         goto exit_errmsg;
298731e31b8aSbellard     }
298831e31b8aSbellard 
29898e62a717SRichard Henderson     i = ehdr->e_phnum * sizeof(struct elf_phdr);
29908e62a717SRichard Henderson     if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) {
29918e62a717SRichard Henderson         phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff);
29929955ffacSRichard Henderson     } else {
29938e62a717SRichard Henderson         phdr = (struct elf_phdr *) alloca(i);
29948e62a717SRichard Henderson         retval = pread(image_fd, phdr, i, ehdr->e_phoff);
29959955ffacSRichard Henderson         if (retval != i) {
29968e62a717SRichard Henderson             goto exit_read;
29979955ffacSRichard Henderson         }
299831e31b8aSbellard     }
29998e62a717SRichard Henderson     bswap_phdr(phdr, ehdr->e_phnum);
300009bfb054Sbellard 
30011af02e83SMike Frysinger     info->nsegs = 0;
30021af02e83SMike Frysinger     info->pt_dynamic_addr = 0;
30031af02e83SMike Frysinger 
300498c1076cSAlex Bennée     mmap_lock();
300598c1076cSAlex Bennée 
30068a1a5274SRichard Henderson     /*
30078a1a5274SRichard Henderson      * Find the maximum size of the image and allocate an appropriate
30088a1a5274SRichard Henderson      * amount of memory to handle that.  Locate the interpreter, if any.
30098a1a5274SRichard Henderson      */
3010682674b8SRichard Henderson     loaddr = -1, hiaddr = 0;
301133143c44SLaurent Vivier     info->alignment = 0;
3012872f3d04SRichard Henderson     info->exec_stack = EXSTACK_DEFAULT;
30138e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; ++i) {
30144d9d535aSRichard Henderson         struct elf_phdr *eppnt = phdr + i;
30154d9d535aSRichard Henderson         if (eppnt->p_type == PT_LOAD) {
30164d9d535aSRichard Henderson             abi_ulong a = eppnt->p_vaddr - eppnt->p_offset;
3017682674b8SRichard Henderson             if (a < loaddr) {
3018682674b8SRichard Henderson                 loaddr = a;
3019682674b8SRichard Henderson             }
3020a3a67f54SRichard Henderson             a = eppnt->p_vaddr + eppnt->p_memsz - 1;
3021682674b8SRichard Henderson             if (a > hiaddr) {
3022682674b8SRichard Henderson                 hiaddr = a;
3023682674b8SRichard Henderson             }
30241af02e83SMike Frysinger             ++info->nsegs;
30254d9d535aSRichard Henderson             info->alignment |= eppnt->p_align;
30268a1a5274SRichard Henderson         } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
30278a1a5274SRichard Henderson             g_autofree char *interp_name = NULL;
30288a1a5274SRichard Henderson 
30298a1a5274SRichard Henderson             if (*pinterp_name) {
3030c7f17e7bSRichard Henderson                 error_setg(&err, "Multiple PT_INTERP entries");
30318a1a5274SRichard Henderson                 goto exit_errmsg;
30328a1a5274SRichard Henderson             }
3033c7f17e7bSRichard Henderson 
30348a1a5274SRichard Henderson             interp_name = g_malloc(eppnt->p_filesz);
30358a1a5274SRichard Henderson 
30368a1a5274SRichard Henderson             if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
30378a1a5274SRichard Henderson                 memcpy(interp_name, bprm_buf + eppnt->p_offset,
30388a1a5274SRichard Henderson                        eppnt->p_filesz);
30398a1a5274SRichard Henderson             } else {
30408a1a5274SRichard Henderson                 retval = pread(image_fd, interp_name, eppnt->p_filesz,
30418a1a5274SRichard Henderson                                eppnt->p_offset);
30428a1a5274SRichard Henderson                 if (retval != eppnt->p_filesz) {
3043c7f17e7bSRichard Henderson                     goto exit_read;
30448a1a5274SRichard Henderson                 }
30458a1a5274SRichard Henderson             }
30468a1a5274SRichard Henderson             if (interp_name[eppnt->p_filesz - 1] != 0) {
3047c7f17e7bSRichard Henderson                 error_setg(&err, "Invalid PT_INTERP entry");
30488a1a5274SRichard Henderson                 goto exit_errmsg;
30498a1a5274SRichard Henderson             }
30508a1a5274SRichard Henderson             *pinterp_name = g_steal_pointer(&interp_name);
305183f990ebSRichard Henderson         } else if (eppnt->p_type == PT_GNU_PROPERTY) {
305283f990ebSRichard Henderson             if (!parse_elf_properties(image_fd, info, eppnt, bprm_buf, &err)) {
305383f990ebSRichard Henderson                 goto exit_errmsg;
305483f990ebSRichard Henderson             }
3055872f3d04SRichard Henderson         } else if (eppnt->p_type == PT_GNU_STACK) {
3056872f3d04SRichard Henderson             info->exec_stack = eppnt->p_flags & PF_X;
3057682674b8SRichard Henderson         }
3058682674b8SRichard Henderson     }
3059682674b8SRichard Henderson 
30601ea06dedSRichard Henderson     load_addr = loaddr;
30611ea06dedSRichard Henderson 
30626fd59449SRichard Henderson     if (pinterp_name != NULL) {
30636fd59449SRichard Henderson         if (ehdr->e_type == ET_EXEC) {
30646fd59449SRichard Henderson             /*
30656fd59449SRichard Henderson              * Make sure that the low address does not conflict with
30666fd59449SRichard Henderson              * MMAP_MIN_ADDR or the QEMU application itself.
30676fd59449SRichard Henderson              */
30686fd59449SRichard Henderson             probe_guest_base(image_name, loaddr, hiaddr);
3069ee947430SAlex Bennée         } else {
30701ea06dedSRichard Henderson             abi_ulong align;
30711ea06dedSRichard Henderson 
3072ee947430SAlex Bennée             /*
3073ee947430SAlex Bennée              * The binary is dynamic, but we still need to
3074ee947430SAlex Bennée              * select guest_base.  In this case we pass a size.
3075ee947430SAlex Bennée              */
3076ee947430SAlex Bennée             probe_guest_base(image_name, 0, hiaddr - loaddr);
30771ea06dedSRichard Henderson 
30781ea06dedSRichard Henderson             /*
30791ea06dedSRichard Henderson              * Avoid collision with the loader by providing a different
30801ea06dedSRichard Henderson              * default load address.
30811ea06dedSRichard Henderson              */
30821ea06dedSRichard Henderson             load_addr += elf_et_dyn_base;
30831ea06dedSRichard Henderson 
30841ea06dedSRichard Henderson             /*
30851ea06dedSRichard Henderson              * TODO: Better support for mmap alignment is desirable.
30861ea06dedSRichard Henderson              * Since we do not have complete control over the guest
30871ea06dedSRichard Henderson              * address space, we prefer the kernel to choose some address
30881ea06dedSRichard Henderson              * rather than force the use of LOAD_ADDR via MAP_FIXED.
30891ea06dedSRichard Henderson              * But without MAP_FIXED we cannot guarantee alignment,
30901ea06dedSRichard Henderson              * only suggest it.
30911ea06dedSRichard Henderson              */
30921ea06dedSRichard Henderson             align = pow2ceil(info->alignment);
30931ea06dedSRichard Henderson             if (align) {
30941ea06dedSRichard Henderson                 load_addr &= -align;
30951ea06dedSRichard Henderson             }
30966fd59449SRichard Henderson         }
30976fd59449SRichard Henderson     }
30986fd59449SRichard Henderson 
30996fd59449SRichard Henderson     /*
31006fd59449SRichard Henderson      * Reserve address space for all of this.
31016fd59449SRichard Henderson      *
3102ad25051bSRichard Henderson      * In the case of ET_EXEC, we supply MAP_FIXED_NOREPLACE so that we get
3103ad25051bSRichard Henderson      * exactly the address range that is required.  Without reserved_va,
3104ad25051bSRichard Henderson      * the guest address space is not isolated.  We have attempted to avoid
3105ad25051bSRichard Henderson      * conflict with the host program itself via probe_guest_base, but using
3106ad25051bSRichard Henderson      * MAP_FIXED_NOREPLACE instead of MAP_FIXED provides an extra check.
31076fd59449SRichard Henderson      *
31086fd59449SRichard Henderson      * Otherwise this is ET_DYN, and we are searching for a location
31096fd59449SRichard Henderson      * that can hold the memory space required.  If the image is
31101ea06dedSRichard Henderson      * pre-linked, LOAD_ADDR will be non-zero, and the kernel should
31116fd59449SRichard Henderson      * honor that address if it happens to be free.
31126fd59449SRichard Henderson      *
31136fd59449SRichard Henderson      * In both cases, we will overwrite pages in this range with mappings
31146fd59449SRichard Henderson      * from the executable.
31156fd59449SRichard Henderson      */
31161ea06dedSRichard Henderson     load_addr = target_mmap(load_addr, (size_t)hiaddr - loaddr + 1, PROT_NONE,
31176fd59449SRichard Henderson                             MAP_PRIVATE | MAP_ANON | MAP_NORESERVE |
3118ad25051bSRichard Henderson                             (ehdr->e_type == ET_EXEC ? MAP_FIXED_NOREPLACE : 0),
311909bfb054Sbellard                             -1, 0);
3120682674b8SRichard Henderson     if (load_addr == -1) {
3121c7f17e7bSRichard Henderson         goto exit_mmap;
312209bfb054Sbellard     }
3123682674b8SRichard Henderson     load_bias = load_addr - loaddr;
312409bfb054Sbellard 
3125a99856cdSChristophe Lyon     if (elf_is_fdpic(ehdr)) {
31261af02e83SMike Frysinger         struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
31277267c094SAnthony Liguori             g_malloc(sizeof(*loadsegs) * info->nsegs);
31281af02e83SMike Frysinger 
31291af02e83SMike Frysinger         for (i = 0; i < ehdr->e_phnum; ++i) {
31301af02e83SMike Frysinger             switch (phdr[i].p_type) {
31311af02e83SMike Frysinger             case PT_DYNAMIC:
31321af02e83SMike Frysinger                 info->pt_dynamic_addr = phdr[i].p_vaddr + load_bias;
31331af02e83SMike Frysinger                 break;
31341af02e83SMike Frysinger             case PT_LOAD:
31351af02e83SMike Frysinger                 loadsegs->addr = phdr[i].p_vaddr + load_bias;
31361af02e83SMike Frysinger                 loadsegs->p_vaddr = phdr[i].p_vaddr;
31371af02e83SMike Frysinger                 loadsegs->p_memsz = phdr[i].p_memsz;
31381af02e83SMike Frysinger                 ++loadsegs;
31391af02e83SMike Frysinger                 break;
31401af02e83SMike Frysinger             }
31411af02e83SMike Frysinger         }
31421af02e83SMike Frysinger     }
31431af02e83SMike Frysinger 
31448e62a717SRichard Henderson     info->load_bias = load_bias;
3145dc12567aSJosh Kunz     info->code_offset = load_bias;
3146dc12567aSJosh Kunz     info->data_offset = load_bias;
31478e62a717SRichard Henderson     info->load_addr = load_addr;
31488e62a717SRichard Henderson     info->entry = ehdr->e_entry + load_bias;
31498e62a717SRichard Henderson     info->start_code = -1;
31508e62a717SRichard Henderson     info->end_code = 0;
31518e62a717SRichard Henderson     info->start_data = -1;
31528e62a717SRichard Henderson     info->end_data = 0;
31531f356e8cSHelge Deller     /* Usual start for brk is after all sections of the main executable. */
31541f356e8cSHelge Deller     info->brk = TARGET_PAGE_ALIGN(hiaddr);
3155d8fd2954SPaul Brook     info->elf_flags = ehdr->e_flags;
31568e62a717SRichard Henderson 
3157e8384b37SRichard Henderson     prot_exec = PROT_EXEC;
3158e8384b37SRichard Henderson #ifdef TARGET_AARCH64
3159e8384b37SRichard Henderson     /*
3160e8384b37SRichard Henderson      * If the BTI feature is present, this indicates that the executable
3161e8384b37SRichard Henderson      * pages of the startup binary should be mapped with PROT_BTI, so that
3162e8384b37SRichard Henderson      * branch targets are enforced.
3163e8384b37SRichard Henderson      *
3164e8384b37SRichard Henderson      * The startup binary is either the interpreter or the static executable.
3165e8384b37SRichard Henderson      * The interpreter is responsible for all pages of a dynamic executable.
3166e8384b37SRichard Henderson      *
3167e8384b37SRichard Henderson      * Elf notes are backward compatible to older cpus.
3168e8384b37SRichard Henderson      * Do not enable BTI unless it is supported.
3169e8384b37SRichard Henderson      */
3170e8384b37SRichard Henderson     if ((info->note_flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
3171e8384b37SRichard Henderson         && (pinterp_name == NULL || *pinterp_name == 0)
3172e8384b37SRichard Henderson         && cpu_isar_feature(aa64_bti, ARM_CPU(thread_cpu))) {
3173e8384b37SRichard Henderson         prot_exec |= TARGET_PROT_BTI;
3174e8384b37SRichard Henderson     }
3175e8384b37SRichard Henderson #endif
3176e8384b37SRichard Henderson 
31778e62a717SRichard Henderson     for (i = 0; i < ehdr->e_phnum; i++) {
31788e62a717SRichard Henderson         struct elf_phdr *eppnt = phdr + i;
317931e31b8aSbellard         if (eppnt->p_type == PT_LOAD) {
31805f4e5b34SRichard Henderson             abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em;
318131e31b8aSbellard             int elf_prot = 0;
318231e31b8aSbellard 
3183e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_R) {
3184e5eaf570SRichard Henderson                 elf_prot |= PROT_READ;
3185e5eaf570SRichard Henderson             }
3186e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_W) {
3187e5eaf570SRichard Henderson                 elf_prot |= PROT_WRITE;
3188e5eaf570SRichard Henderson             }
3189e5eaf570SRichard Henderson             if (eppnt->p_flags & PF_X) {
3190e8384b37SRichard Henderson                 elf_prot |= prot_exec;
3191e5eaf570SRichard Henderson             }
319231e31b8aSbellard 
3193682674b8SRichard Henderson             vaddr = load_bias + eppnt->p_vaddr;
3194e3d97d5cSRichard Henderson             vaddr_po = vaddr & ~TARGET_PAGE_MASK;
3195e3d97d5cSRichard Henderson             vaddr_ps = vaddr & TARGET_PAGE_MASK;
319622d113b5SGiuseppe Musacchio 
319722d113b5SGiuseppe Musacchio             vaddr_ef = vaddr + eppnt->p_filesz;
319822d113b5SGiuseppe Musacchio             vaddr_em = vaddr + eppnt->p_memsz;
3199682674b8SRichard Henderson 
3200d87146bcSGiuseppe Musacchio             /*
320122d113b5SGiuseppe Musacchio              * Some segments may be completely empty, with a non-zero p_memsz
320222d113b5SGiuseppe Musacchio              * but no backing file segment.
3203d87146bcSGiuseppe Musacchio              */
3204d87146bcSGiuseppe Musacchio             if (eppnt->p_filesz != 0) {
32055f4e5b34SRichard Henderson                 error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
32065f4e5b34SRichard Henderson                                     elf_prot, MAP_PRIVATE | MAP_FIXED,
32078e62a717SRichard Henderson                                     image_fd, eppnt->p_offset - vaddr_po);
3208e89f07d3Spbrook                 if (error == -1) {
3209c7f17e7bSRichard Henderson                     goto exit_mmap;
321031e31b8aSbellard                 }
32115f4e5b34SRichard Henderson             }
321231e31b8aSbellard 
32135f4e5b34SRichard Henderson             /* If the load segment requests extra zeros (e.g. bss), map it. */
32145f4e5b34SRichard Henderson             if (vaddr_ef < vaddr_em &&
32152d385be6SRichard Henderson                 !zero_bss(vaddr_ef, vaddr_em, elf_prot)) {
32162d385be6SRichard Henderson                 goto exit_mmap;
3217682674b8SRichard Henderson             }
32188e62a717SRichard Henderson 
32198e62a717SRichard Henderson             /* Find the full program boundaries.  */
32208e62a717SRichard Henderson             if (elf_prot & PROT_EXEC) {
32218e62a717SRichard Henderson                 if (vaddr < info->start_code) {
32228e62a717SRichard Henderson                     info->start_code = vaddr;
3223cf129f3aSRichard Henderson                 }
32248e62a717SRichard Henderson                 if (vaddr_ef > info->end_code) {
32258e62a717SRichard Henderson                     info->end_code = vaddr_ef;
32268e62a717SRichard Henderson                 }
32278e62a717SRichard Henderson             }
32288e62a717SRichard Henderson             if (elf_prot & PROT_WRITE) {
32298e62a717SRichard Henderson                 if (vaddr < info->start_data) {
32308e62a717SRichard Henderson                     info->start_data = vaddr;
32318e62a717SRichard Henderson                 }
32328e62a717SRichard Henderson                 if (vaddr_ef > info->end_data) {
32338e62a717SRichard Henderson                     info->end_data = vaddr_ef;
32348e62a717SRichard Henderson                 }
32358a045188STimothy E Baldwin             }
32365dd0db52SStefan Markovic #ifdef TARGET_MIPS
32375dd0db52SStefan Markovic         } else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
32385dd0db52SStefan Markovic             Mips_elf_abiflags_v0 abiflags;
32395dd0db52SStefan Markovic             if (eppnt->p_filesz < sizeof(Mips_elf_abiflags_v0)) {
3240c7f17e7bSRichard Henderson                 error_setg(&err, "Invalid PT_MIPS_ABIFLAGS entry");
32415dd0db52SStefan Markovic                 goto exit_errmsg;
32425dd0db52SStefan Markovic             }
32435dd0db52SStefan Markovic             if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
32445dd0db52SStefan Markovic                 memcpy(&abiflags, bprm_buf + eppnt->p_offset,
32455dd0db52SStefan Markovic                        sizeof(Mips_elf_abiflags_v0));
32465dd0db52SStefan Markovic             } else {
32475dd0db52SStefan Markovic                 retval = pread(image_fd, &abiflags, sizeof(Mips_elf_abiflags_v0),
32485dd0db52SStefan Markovic                                eppnt->p_offset);
32495dd0db52SStefan Markovic                 if (retval != sizeof(Mips_elf_abiflags_v0)) {
3250c7f17e7bSRichard Henderson                     goto exit_read;
32515dd0db52SStefan Markovic                 }
32525dd0db52SStefan Markovic             }
32535dd0db52SStefan Markovic             bswap_mips_abiflags(&abiflags);
3254c94cb6c9SStefan Markovic             info->fp_abi = abiflags.fp_abi;
32555dd0db52SStefan Markovic #endif
32568e62a717SRichard Henderson         }
32578e62a717SRichard Henderson     }
32588e62a717SRichard Henderson 
32598e62a717SRichard Henderson     if (info->end_data == 0) {
32608e62a717SRichard Henderson         info->start_data = info->end_code;
32618e62a717SRichard Henderson         info->end_data = info->end_code;
326231e31b8aSbellard     }
326331e31b8aSbellard 
3264682674b8SRichard Henderson     if (qemu_log_enabled()) {
32658e62a717SRichard Henderson         load_symbols(ehdr, image_fd, load_bias);
3266682674b8SRichard Henderson     }
326731e31b8aSbellard 
32687c10cb38SIlya Leoshkevich     debuginfo_report_elf(image_name, image_fd, load_bias);
32697c10cb38SIlya Leoshkevich 
327098c1076cSAlex Bennée     mmap_unlock();
327198c1076cSAlex Bennée 
32728e62a717SRichard Henderson     close(image_fd);
32738e62a717SRichard Henderson     return;
327431e31b8aSbellard 
32758e62a717SRichard Henderson  exit_read:
32768e62a717SRichard Henderson     if (retval >= 0) {
3277c7f17e7bSRichard Henderson         error_setg(&err, "Incomplete read of file header");
3278c7f17e7bSRichard Henderson     } else {
3279c7f17e7bSRichard Henderson         error_setg_errno(&err, errno, "Error reading file header");
32808e62a717SRichard Henderson     }
3281c7f17e7bSRichard Henderson     goto exit_errmsg;
3282c7f17e7bSRichard Henderson  exit_mmap:
3283c7f17e7bSRichard Henderson     error_setg_errno(&err, errno, "Error mapping file");
3284c7f17e7bSRichard Henderson     goto exit_errmsg;
32858e62a717SRichard Henderson  exit_errmsg:
3286c7f17e7bSRichard Henderson     error_reportf_err(err, "%s: ", image_name);
32878e62a717SRichard Henderson     exit(-1);
32888e62a717SRichard Henderson }
32898e62a717SRichard Henderson 
32908e62a717SRichard Henderson static void load_elf_interp(const char *filename, struct image_info *info,
32918e62a717SRichard Henderson                             char bprm_buf[BPRM_BUF_SIZE])
32928e62a717SRichard Henderson {
32938e62a717SRichard Henderson     int fd, retval;
3294808f6563SRichard Henderson     Error *err = NULL;
32958e62a717SRichard Henderson 
32968e62a717SRichard Henderson     fd = open(path(filename), O_RDONLY);
32978e62a717SRichard Henderson     if (fd < 0) {
3298808f6563SRichard Henderson         error_setg_file_open(&err, errno, filename);
3299808f6563SRichard Henderson         error_report_err(err);
3300808f6563SRichard Henderson         exit(-1);
33018e62a717SRichard Henderson     }
33028e62a717SRichard Henderson 
33038e62a717SRichard Henderson     retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
33048e62a717SRichard Henderson     if (retval < 0) {
3305808f6563SRichard Henderson         error_setg_errno(&err, errno, "Error reading file header");
3306808f6563SRichard Henderson         error_reportf_err(err, "%s: ", filename);
3307808f6563SRichard Henderson         exit(-1);
33088e62a717SRichard Henderson     }
3309808f6563SRichard Henderson 
33108e62a717SRichard Henderson     if (retval < BPRM_BUF_SIZE) {
33118e62a717SRichard Henderson         memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
33128e62a717SRichard Henderson     }
33138e62a717SRichard Henderson 
3314bf858897SRichard Henderson     load_elf_image(filename, fd, info, NULL, bprm_buf);
331531e31b8aSbellard }
331631e31b8aSbellard 
331749918a75Spbrook static int symfind(const void *s0, const void *s1)
331849918a75Spbrook {
331949918a75Spbrook     struct elf_sym *sym = (struct elf_sym *)s1;
3320b6235a75SRichard Henderson     __typeof(sym->st_value) addr = *(uint64_t *)s0;
332149918a75Spbrook     int result = 0;
3322b6235a75SRichard Henderson 
3323c7c530cdSStefan Weil     if (addr < sym->st_value) {
332449918a75Spbrook         result = -1;
3325c7c530cdSStefan Weil     } else if (addr >= sym->st_value + sym->st_size) {
332649918a75Spbrook         result = 1;
332749918a75Spbrook     }
332849918a75Spbrook     return result;
332949918a75Spbrook }
333049918a75Spbrook 
3331b6235a75SRichard Henderson static const char *lookup_symbolxx(struct syminfo *s, uint64_t orig_addr)
333249918a75Spbrook {
333349918a75Spbrook #if ELF_CLASS == ELFCLASS32
333449918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf32;
333549918a75Spbrook #else
333649918a75Spbrook     struct elf_sym *syms = s->disas_symtab.elf64;
333749918a75Spbrook #endif
333849918a75Spbrook 
333949918a75Spbrook     // binary search
334049918a75Spbrook     struct elf_sym *sym;
334149918a75Spbrook 
3342c7c530cdSStefan Weil     sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms), symfind);
33437cba04f6SBlue Swirl     if (sym != NULL) {
334449918a75Spbrook         return s->disas_strtab + sym->st_name;
334549918a75Spbrook     }
334649918a75Spbrook 
334749918a75Spbrook     return "";
334849918a75Spbrook }
334949918a75Spbrook 
335049918a75Spbrook /* FIXME: This should use elf_ops.h  */
335149918a75Spbrook static int symcmp(const void *s0, const void *s1)
335249918a75Spbrook {
335349918a75Spbrook     struct elf_sym *sym0 = (struct elf_sym *)s0;
335449918a75Spbrook     struct elf_sym *sym1 = (struct elf_sym *)s1;
335549918a75Spbrook     return (sym0->st_value < sym1->st_value)
335649918a75Spbrook         ? -1
335749918a75Spbrook         : ((sym0->st_value > sym1->st_value) ? 1 : 0);
335849918a75Spbrook }
335949918a75Spbrook 
3360689f936fSbellard /* Best attempt to load symbols from this ELF object. */
3361682674b8SRichard Henderson static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
3362689f936fSbellard {
3363682674b8SRichard Henderson     int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
33641e06262dSPeter Maydell     uint64_t segsz;
3365682674b8SRichard Henderson     struct elf_shdr *shdr;
3366b9475279SCédric VINCENT     char *strings = NULL;
3367b9475279SCédric VINCENT     struct syminfo *s = NULL;
3368b9475279SCédric VINCENT     struct elf_sym *new_syms, *syms = NULL;
336931e31b8aSbellard 
3370682674b8SRichard Henderson     shnum = hdr->e_shnum;
3371682674b8SRichard Henderson     i = shnum * sizeof(struct elf_shdr);
3372682674b8SRichard Henderson     shdr = (struct elf_shdr *)alloca(i);
3373682674b8SRichard Henderson     if (pread(fd, shdr, i, hdr->e_shoff) != i) {
3374689f936fSbellard         return;
3375682674b8SRichard Henderson     }
3376682674b8SRichard Henderson 
3377682674b8SRichard Henderson     bswap_shdr(shdr, shnum);
3378682674b8SRichard Henderson     for (i = 0; i < shnum; ++i) {
3379682674b8SRichard Henderson         if (shdr[i].sh_type == SHT_SYMTAB) {
3380682674b8SRichard Henderson             sym_idx = i;
3381682674b8SRichard Henderson             str_idx = shdr[i].sh_link;
3382689f936fSbellard             goto found;
3383689f936fSbellard         }
3384689f936fSbellard     }
3385682674b8SRichard Henderson 
3386682674b8SRichard Henderson     /* There will be no symbol table if the file was stripped.  */
3387682674b8SRichard Henderson     return;
3388689f936fSbellard 
3389689f936fSbellard  found:
3390689f936fSbellard     /* Now know where the strtab and symtab are.  Snarf them.  */
33910ef9ea29SPeter Maydell     s = g_try_new(struct syminfo, 1);
3392682674b8SRichard Henderson     if (!s) {
3393b9475279SCédric VINCENT         goto give_up;
3394682674b8SRichard Henderson     }
3395682674b8SRichard Henderson 
33961e06262dSPeter Maydell     segsz = shdr[str_idx].sh_size;
33971e06262dSPeter Maydell     s->disas_strtab = strings = g_try_malloc(segsz);
33981e06262dSPeter Maydell     if (!strings ||
33991e06262dSPeter Maydell         pread(fd, strings, segsz, shdr[str_idx].sh_offset) != segsz) {
3400b9475279SCédric VINCENT         goto give_up;
3401682674b8SRichard Henderson     }
3402689f936fSbellard 
34031e06262dSPeter Maydell     segsz = shdr[sym_idx].sh_size;
34041e06262dSPeter Maydell     syms = g_try_malloc(segsz);
34051e06262dSPeter Maydell     if (!syms || pread(fd, syms, segsz, shdr[sym_idx].sh_offset) != segsz) {
3406b9475279SCédric VINCENT         goto give_up;
3407682674b8SRichard Henderson     }
3408689f936fSbellard 
34091e06262dSPeter Maydell     if (segsz / sizeof(struct elf_sym) > INT_MAX) {
34101e06262dSPeter Maydell         /* Implausibly large symbol table: give up rather than ploughing
34111e06262dSPeter Maydell          * on with the number of symbols calculation overflowing
34121e06262dSPeter Maydell          */
34131e06262dSPeter Maydell         goto give_up;
34141e06262dSPeter Maydell     }
34151e06262dSPeter Maydell     nsyms = segsz / sizeof(struct elf_sym);
3416682674b8SRichard Henderson     for (i = 0; i < nsyms; ) {
341749918a75Spbrook         bswap_sym(syms + i);
3418682674b8SRichard Henderson         /* Throw away entries which we do not need.  */
3419682674b8SRichard Henderson         if (syms[i].st_shndx == SHN_UNDEF
3420682674b8SRichard Henderson             || syms[i].st_shndx >= SHN_LORESERVE
3421682674b8SRichard Henderson             || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
3422682674b8SRichard Henderson             if (i < --nsyms) {
342349918a75Spbrook                 syms[i] = syms[nsyms];
342449918a75Spbrook             }
3425682674b8SRichard Henderson         } else {
342649918a75Spbrook #if defined(TARGET_ARM) || defined (TARGET_MIPS)
342749918a75Spbrook             /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
342849918a75Spbrook             syms[i].st_value &= ~(target_ulong)1;
342949918a75Spbrook #endif
3430682674b8SRichard Henderson             syms[i].st_value += load_bias;
343149918a75Spbrook             i++;
343249918a75Spbrook         }
3433682674b8SRichard Henderson     }
343449918a75Spbrook 
3435b9475279SCédric VINCENT     /* No "useful" symbol.  */
3436b9475279SCédric VINCENT     if (nsyms == 0) {
3437b9475279SCédric VINCENT         goto give_up;
3438b9475279SCédric VINCENT     }
3439b9475279SCédric VINCENT 
34405d5c9930SRichard Henderson     /* Attempt to free the storage associated with the local symbols
34415d5c9930SRichard Henderson        that we threw away.  Whether or not this has any effect on the
34425d5c9930SRichard Henderson        memory allocation depends on the malloc implementation and how
34435d5c9930SRichard Henderson        many symbols we managed to discard.  */
34440ef9ea29SPeter Maydell     new_syms = g_try_renew(struct elf_sym, syms, nsyms);
34458d79de6eSStefan Weil     if (new_syms == NULL) {
3446b9475279SCédric VINCENT         goto give_up;
34475d5c9930SRichard Henderson     }
34488d79de6eSStefan Weil     syms = new_syms;
34495d5c9930SRichard Henderson 
345049918a75Spbrook     qsort(syms, nsyms, sizeof(*syms), symcmp);
345149918a75Spbrook 
345249918a75Spbrook     s->disas_num_syms = nsyms;
345349918a75Spbrook #if ELF_CLASS == ELFCLASS32
345449918a75Spbrook     s->disas_symtab.elf32 = syms;
345549918a75Spbrook #else
345649918a75Spbrook     s->disas_symtab.elf64 = syms;
345749918a75Spbrook #endif
3458682674b8SRichard Henderson     s->lookup_symbol = lookup_symbolxx;
3459e80cfcfcSbellard     s->next = syminfos;
3460e80cfcfcSbellard     syminfos = s;
3461b9475279SCédric VINCENT 
3462b9475279SCédric VINCENT     return;
3463b9475279SCédric VINCENT 
3464b9475279SCédric VINCENT give_up:
34650ef9ea29SPeter Maydell     g_free(s);
34660ef9ea29SPeter Maydell     g_free(strings);
34670ef9ea29SPeter Maydell     g_free(syms);
3468689f936fSbellard }
346931e31b8aSbellard 
3470768fe76eSYunQiang Su uint32_t get_elf_eflags(int fd)
3471768fe76eSYunQiang Su {
3472768fe76eSYunQiang Su     struct elfhdr ehdr;
3473768fe76eSYunQiang Su     off_t offset;
3474768fe76eSYunQiang Su     int ret;
3475768fe76eSYunQiang Su 
3476768fe76eSYunQiang Su     /* Read ELF header */
3477768fe76eSYunQiang Su     offset = lseek(fd, 0, SEEK_SET);
3478768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3479768fe76eSYunQiang Su         return 0;
3480768fe76eSYunQiang Su     }
3481768fe76eSYunQiang Su     ret = read(fd, &ehdr, sizeof(ehdr));
3482768fe76eSYunQiang Su     if (ret < sizeof(ehdr)) {
3483768fe76eSYunQiang Su         return 0;
3484768fe76eSYunQiang Su     }
3485768fe76eSYunQiang Su     offset = lseek(fd, offset, SEEK_SET);
3486768fe76eSYunQiang Su     if (offset == (off_t) -1) {
3487768fe76eSYunQiang Su         return 0;
3488768fe76eSYunQiang Su     }
3489768fe76eSYunQiang Su 
3490768fe76eSYunQiang Su     /* Check ELF signature */
3491768fe76eSYunQiang Su     if (!elf_check_ident(&ehdr)) {
3492768fe76eSYunQiang Su         return 0;
3493768fe76eSYunQiang Su     }
3494768fe76eSYunQiang Su 
3495768fe76eSYunQiang Su     /* check header */
3496768fe76eSYunQiang Su     bswap_ehdr(&ehdr);
3497768fe76eSYunQiang Su     if (!elf_check_ehdr(&ehdr)) {
3498768fe76eSYunQiang Su         return 0;
3499768fe76eSYunQiang Su     }
3500768fe76eSYunQiang Su 
3501768fe76eSYunQiang Su     /* return architecture id */
3502768fe76eSYunQiang Su     return ehdr.e_flags;
3503768fe76eSYunQiang Su }
3504768fe76eSYunQiang Su 
3505f0116c54SWill Newton int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
350631e31b8aSbellard {
35078e62a717SRichard Henderson     struct image_info interp_info;
350831e31b8aSbellard     struct elfhdr elf_ex;
35098e62a717SRichard Henderson     char *elf_interpreter = NULL;
351059baae9aSStefan Brüns     char *scratch;
351131e31b8aSbellard 
3512abcac736SDaniel Santos     memset(&interp_info, 0, sizeof(interp_info));
3513abcac736SDaniel Santos #ifdef TARGET_MIPS
3514abcac736SDaniel Santos     interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
3515abcac736SDaniel Santos #endif
3516abcac736SDaniel Santos 
3517bf858897SRichard Henderson     info->start_mmap = (abi_ulong)ELF_START_MMAP;
351831e31b8aSbellard 
3519bf858897SRichard Henderson     load_elf_image(bprm->filename, bprm->fd, info,
3520bf858897SRichard Henderson                    &elf_interpreter, bprm->buf);
3521bf858897SRichard Henderson 
3522bf858897SRichard Henderson     /* ??? We need a copy of the elf header for passing to create_elf_tables.
3523bf858897SRichard Henderson        If we do nothing, we'll have overwritten this when we re-use bprm->buf
3524bf858897SRichard Henderson        when we load the interpreter.  */
3525bf858897SRichard Henderson     elf_ex = *(struct elfhdr *)bprm->buf;
352631e31b8aSbellard 
352759baae9aSStefan Brüns     /* Do this so that we can load the interpreter, if need be.  We will
352859baae9aSStefan Brüns        change some of these later */
352959baae9aSStefan Brüns     bprm->p = setup_arg_pages(bprm, info);
353059baae9aSStefan Brüns 
353159baae9aSStefan Brüns     scratch = g_new0(char, TARGET_PAGE_SIZE);
35327c4ee5bcSRichard Henderson     if (STACK_GROWS_DOWN) {
353359baae9aSStefan Brüns         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
353459baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
35357c4ee5bcSRichard Henderson         info->file_string = bprm->p;
353659baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
353759baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
35387c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
353959baae9aSStefan Brüns         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
354059baae9aSStefan Brüns                                    bprm->p, info->stack_limit);
35417c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
35427c4ee5bcSRichard Henderson     } else {
35437c4ee5bcSRichard Henderson         info->arg_strings = bprm->p;
35447c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
35457c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
35467c4ee5bcSRichard Henderson         info->env_strings = bprm->p;
35477c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
35487c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
35497c4ee5bcSRichard Henderson         info->file_string = bprm->p;
35507c4ee5bcSRichard Henderson         bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
35517c4ee5bcSRichard Henderson                                    bprm->p, info->stack_limit);
35527c4ee5bcSRichard Henderson     }
35537c4ee5bcSRichard Henderson 
355459baae9aSStefan Brüns     g_free(scratch);
355559baae9aSStefan Brüns 
3556e5fe0c52Spbrook     if (!bprm->p) {
3557bf858897SRichard Henderson         fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
355831e31b8aSbellard         exit(-1);
35599955ffacSRichard Henderson     }
3560379f6698SPaul Brook 
35618e62a717SRichard Henderson     if (elf_interpreter) {
35628e62a717SRichard Henderson         load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
356331e31b8aSbellard 
35641f356e8cSHelge Deller         /*
35651f356e8cSHelge Deller          * While unusual because of ELF_ET_DYN_BASE, if we are unlucky
35661f356e8cSHelge Deller          * with the mappings the interpreter can be loaded above but
35671f356e8cSHelge Deller          * near the main executable, which can leave very little room
35681f356e8cSHelge Deller          * for the heap.
35691f356e8cSHelge Deller          * If the current brk has less than 16MB, use the end of the
35701f356e8cSHelge Deller          * interpreter.
35711f356e8cSHelge Deller          */
35721f356e8cSHelge Deller         if (interp_info.brk > info->brk &&
35731f356e8cSHelge Deller             interp_info.load_bias - info->brk < 16 * MiB)  {
35741f356e8cSHelge Deller             info->brk = interp_info.brk;
35751f356e8cSHelge Deller         }
35761f356e8cSHelge Deller 
35778e62a717SRichard Henderson         /* If the program interpreter is one of these two, then assume
35788e62a717SRichard Henderson            an iBCS2 image.  Otherwise assume a native linux image.  */
357931e31b8aSbellard 
35808e62a717SRichard Henderson         if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0
35818e62a717SRichard Henderson             || strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) {
35828e62a717SRichard Henderson             info->personality = PER_SVR4;
35838e62a717SRichard Henderson 
358431e31b8aSbellard             /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
35858e62a717SRichard Henderson                and some applications "depend" upon this behavior.  Since
35868e62a717SRichard Henderson                we do not have the power to recompile these, we emulate
35878e62a717SRichard Henderson                the SVr4 behavior.  Sigh.  */
35888e62a717SRichard Henderson             target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
358968754b44SPeter Maydell                         MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
359031e31b8aSbellard         }
3591c94cb6c9SStefan Markovic #ifdef TARGET_MIPS
3592c94cb6c9SStefan Markovic         info->interp_fp_abi = interp_info.fp_abi;
3593c94cb6c9SStefan Markovic #endif
35948e62a717SRichard Henderson     }
359531e31b8aSbellard 
3596db2af69dSRichard Henderson     /*
3597db2af69dSRichard Henderson      * TODO: load a vdso, which would also contain the signal trampolines.
3598db2af69dSRichard Henderson      * Otherwise, allocate a private page to hold them.
3599db2af69dSRichard Henderson      */
3600db2af69dSRichard Henderson     if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
3601802ae45eSLaurent Vivier         abi_long tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
3602db2af69dSRichard Henderson                                           PROT_READ | PROT_WRITE,
3603db2af69dSRichard Henderson                                           MAP_PRIVATE | MAP_ANON, -1, 0);
3604802ae45eSLaurent Vivier         if (tramp_page == -1) {
3605802ae45eSLaurent Vivier             return -errno;
3606802ae45eSLaurent Vivier         }
3607802ae45eSLaurent Vivier 
3608db2af69dSRichard Henderson         setup_sigtramp(tramp_page);
3609db2af69dSRichard Henderson         target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
3610db2af69dSRichard Henderson     }
3611db2af69dSRichard Henderson 
36128e62a717SRichard Henderson     bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
36138e62a717SRichard Henderson                                 info, (elf_interpreter ? &interp_info : NULL));
36148e62a717SRichard Henderson     info->start_stack = bprm->p;
36158e62a717SRichard Henderson 
36168e62a717SRichard Henderson     /* If we have an interpreter, set that as the program's entry point.
36178e78064eSRichard Henderson        Copy the load_bias as well, to help PPC64 interpret the entry
36188e62a717SRichard Henderson        point as a function descriptor.  Do this after creating elf tables
36198e62a717SRichard Henderson        so that we copy the original program entry point into the AUXV.  */
36208e62a717SRichard Henderson     if (elf_interpreter) {
36218e78064eSRichard Henderson         info->load_bias = interp_info.load_bias;
36228e62a717SRichard Henderson         info->entry = interp_info.entry;
36232b323087SPhilippe Mathieu-Daudé         g_free(elf_interpreter);
36248e62a717SRichard Henderson     }
362531e31b8aSbellard 
3626edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3627edf8e2afSMika Westerberg     bprm->core_dump = &elf_core_dump;
3628edf8e2afSMika Westerberg #endif
3629edf8e2afSMika Westerberg 
363031e31b8aSbellard     return 0;
363131e31b8aSbellard }
363231e31b8aSbellard 
3633edf8e2afSMika Westerberg #ifdef USE_ELF_CORE_DUMP
3634edf8e2afSMika Westerberg /*
3635edf8e2afSMika Westerberg  * Definitions to generate Intel SVR4-like core files.
3636a2547a13SLaurent Desnogues  * These mostly have the same names as the SVR4 types with "target_elf_"
3637edf8e2afSMika Westerberg  * tacked on the front to prevent clashes with linux definitions,
3638edf8e2afSMika Westerberg  * and the typedef forms have been avoided.  This is mostly like
3639edf8e2afSMika Westerberg  * the SVR4 structure, but more Linuxy, with things that Linux does
3640edf8e2afSMika Westerberg  * not support and which gdb doesn't really use excluded.
3641edf8e2afSMika Westerberg  *
3642edf8e2afSMika Westerberg  * Fields we don't dump (their contents is zero) in linux-user qemu
3643edf8e2afSMika Westerberg  * are marked with XXX.
3644edf8e2afSMika Westerberg  *
3645edf8e2afSMika Westerberg  * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
3646edf8e2afSMika Westerberg  *
3647edf8e2afSMika Westerberg  * Porting ELF coredump for target is (quite) simple process.  First you
3648dd0a3651SNathan Froyd  * define USE_ELF_CORE_DUMP in target ELF code (where init_thread() for
3649edf8e2afSMika Westerberg  * the target resides):
3650edf8e2afSMika Westerberg  *
3651edf8e2afSMika Westerberg  * #define USE_ELF_CORE_DUMP
3652edf8e2afSMika Westerberg  *
3653edf8e2afSMika Westerberg  * Next you define type of register set used for dumping.  ELF specification
3654edf8e2afSMika Westerberg  * says that it needs to be array of elf_greg_t that has size of ELF_NREG.
3655edf8e2afSMika Westerberg  *
3656c227f099SAnthony Liguori  * typedef <target_regtype> target_elf_greg_t;
3657edf8e2afSMika Westerberg  * #define ELF_NREG <number of registers>
3658c227f099SAnthony Liguori  * typedef taret_elf_greg_t target_elf_gregset_t[ELF_NREG];
3659edf8e2afSMika Westerberg  *
3660edf8e2afSMika Westerberg  * Last step is to implement target specific function that copies registers
3661edf8e2afSMika Westerberg  * from given cpu into just specified register set.  Prototype is:
3662edf8e2afSMika Westerberg  *
3663c227f099SAnthony Liguori  * static void elf_core_copy_regs(taret_elf_gregset_t *regs,
36649349b4f9SAndreas Färber  *                                const CPUArchState *env);
3665edf8e2afSMika Westerberg  *
3666edf8e2afSMika Westerberg  * Parameters:
3667edf8e2afSMika Westerberg  *     regs - copy register values into here (allocated and zeroed by caller)
3668edf8e2afSMika Westerberg  *     env - copy registers from here
3669edf8e2afSMika Westerberg  *
3670edf8e2afSMika Westerberg  * Example for ARM target is provided in this file.
3671edf8e2afSMika Westerberg  */
3672edf8e2afSMika Westerberg 
3673edf8e2afSMika Westerberg /* An ELF note in memory */
3674edf8e2afSMika Westerberg struct memelfnote {
3675edf8e2afSMika Westerberg     const char *name;
3676edf8e2afSMika Westerberg     size_t     namesz;
3677edf8e2afSMika Westerberg     size_t     namesz_rounded;
3678edf8e2afSMika Westerberg     int        type;
3679edf8e2afSMika Westerberg     size_t     datasz;
368080f5ce75SLaurent Vivier     size_t     datasz_rounded;
3681edf8e2afSMika Westerberg     void       *data;
3682edf8e2afSMika Westerberg     size_t     notesz;
3683edf8e2afSMika Westerberg };
3684edf8e2afSMika Westerberg 
3685a2547a13SLaurent Desnogues struct target_elf_siginfo {
3686f8fd4fc4SPaolo Bonzini     abi_int    si_signo; /* signal number */
3687f8fd4fc4SPaolo Bonzini     abi_int    si_code;  /* extra code */
3688f8fd4fc4SPaolo Bonzini     abi_int    si_errno; /* errno */
3689edf8e2afSMika Westerberg };
3690edf8e2afSMika Westerberg 
3691a2547a13SLaurent Desnogues struct target_elf_prstatus {
3692a2547a13SLaurent Desnogues     struct target_elf_siginfo pr_info;      /* Info associated with signal */
36931ddd592fSPaolo Bonzini     abi_short          pr_cursig;    /* Current signal */
3694ca98ac83SPaolo Bonzini     abi_ulong          pr_sigpend;   /* XXX */
3695ca98ac83SPaolo Bonzini     abi_ulong          pr_sighold;   /* XXX */
3696c227f099SAnthony Liguori     target_pid_t       pr_pid;
3697c227f099SAnthony Liguori     target_pid_t       pr_ppid;
3698c227f099SAnthony Liguori     target_pid_t       pr_pgrp;
3699c227f099SAnthony Liguori     target_pid_t       pr_sid;
3700edf8e2afSMika Westerberg     struct target_timeval pr_utime;  /* XXX User time */
3701edf8e2afSMika Westerberg     struct target_timeval pr_stime;  /* XXX System time */
3702edf8e2afSMika Westerberg     struct target_timeval pr_cutime; /* XXX Cumulative user time */
3703edf8e2afSMika Westerberg     struct target_timeval pr_cstime; /* XXX Cumulative system time */
3704c227f099SAnthony Liguori     target_elf_gregset_t      pr_reg;       /* GP registers */
3705f8fd4fc4SPaolo Bonzini     abi_int            pr_fpvalid;   /* XXX */
3706edf8e2afSMika Westerberg };
3707edf8e2afSMika Westerberg 
3708edf8e2afSMika Westerberg #define ELF_PRARGSZ     (80) /* Number of chars for args */
3709edf8e2afSMika Westerberg 
3710a2547a13SLaurent Desnogues struct target_elf_prpsinfo {
3711edf8e2afSMika Westerberg     char         pr_state;       /* numeric process state */
3712edf8e2afSMika Westerberg     char         pr_sname;       /* char for pr_state */
3713edf8e2afSMika Westerberg     char         pr_zomb;        /* zombie */
3714edf8e2afSMika Westerberg     char         pr_nice;        /* nice val */
3715ca98ac83SPaolo Bonzini     abi_ulong    pr_flag;        /* flags */
3716c227f099SAnthony Liguori     target_uid_t pr_uid;
3717c227f099SAnthony Liguori     target_gid_t pr_gid;
3718c227f099SAnthony Liguori     target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
3719edf8e2afSMika Westerberg     /* Lots missing */
3720d7eb2b92SAlistair Francis     char    pr_fname[16] QEMU_NONSTRING; /* filename of executable */
3721edf8e2afSMika Westerberg     char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
3722edf8e2afSMika Westerberg };
3723edf8e2afSMika Westerberg 
3724edf8e2afSMika Westerberg /* Here is the structure in which status of each thread is captured. */
3725edf8e2afSMika Westerberg struct elf_thread_status {
372672cf2d4fSBlue Swirl     QTAILQ_ENTRY(elf_thread_status)  ets_link;
3727a2547a13SLaurent Desnogues     struct target_elf_prstatus prstatus;   /* NT_PRSTATUS */
3728edf8e2afSMika Westerberg #if 0
3729edf8e2afSMika Westerberg     elf_fpregset_t fpu;             /* NT_PRFPREG */
3730edf8e2afSMika Westerberg     struct task_struct *thread;
3731edf8e2afSMika Westerberg     elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
3732edf8e2afSMika Westerberg #endif
3733edf8e2afSMika Westerberg     struct memelfnote notes[1];
3734edf8e2afSMika Westerberg     int num_notes;
3735edf8e2afSMika Westerberg };
3736edf8e2afSMika Westerberg 
3737edf8e2afSMika Westerberg struct elf_note_info {
3738edf8e2afSMika Westerberg     struct memelfnote   *notes;
3739a2547a13SLaurent Desnogues     struct target_elf_prstatus *prstatus;  /* NT_PRSTATUS */
3740a2547a13SLaurent Desnogues     struct target_elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
3741edf8e2afSMika Westerberg 
3742b58deb34SPaolo Bonzini     QTAILQ_HEAD(, elf_thread_status) thread_list;
3743edf8e2afSMika Westerberg #if 0
3744edf8e2afSMika Westerberg     /*
3745edf8e2afSMika Westerberg      * Current version of ELF coredump doesn't support
3746edf8e2afSMika Westerberg      * dumping fp regs etc.
3747edf8e2afSMika Westerberg      */
3748edf8e2afSMika Westerberg     elf_fpregset_t *fpu;
3749edf8e2afSMika Westerberg     elf_fpxregset_t *xfpu;
3750edf8e2afSMika Westerberg     int thread_status_size;
3751edf8e2afSMika Westerberg #endif
3752edf8e2afSMika Westerberg     int notes_size;
3753edf8e2afSMika Westerberg     int numnote;
3754edf8e2afSMika Westerberg };
3755edf8e2afSMika Westerberg 
3756edf8e2afSMika Westerberg struct vm_area_struct {
37571a1c4db9SMikhail Ilyin     target_ulong   vma_start;  /* start vaddr of memory region */
37581a1c4db9SMikhail Ilyin     target_ulong   vma_end;    /* end vaddr of memory region */
3759edf8e2afSMika Westerberg     abi_ulong      vma_flags;  /* protection etc. flags for the region */
376072cf2d4fSBlue Swirl     QTAILQ_ENTRY(vm_area_struct) vma_link;
3761edf8e2afSMika Westerberg };
3762edf8e2afSMika Westerberg 
3763edf8e2afSMika Westerberg struct mm_struct {
376472cf2d4fSBlue Swirl     QTAILQ_HEAD(, vm_area_struct) mm_mmap;
3765edf8e2afSMika Westerberg     int mm_count;           /* number of mappings */
3766edf8e2afSMika Westerberg };
3767edf8e2afSMika Westerberg 
3768edf8e2afSMika Westerberg static struct mm_struct *vma_init(void);
3769edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *);
37701a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *, target_ulong,
37711a1c4db9SMikhail Ilyin                            target_ulong, abi_ulong);
3772edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *);
3773edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *);
3774edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *);
3775edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *);
37761a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
3777edf8e2afSMika Westerberg                       unsigned long flags);
3778edf8e2afSMika Westerberg 
3779edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
3780edf8e2afSMika Westerberg static void fill_note(struct memelfnote *, const char *, int,
3781edf8e2afSMika Westerberg                       unsigned int, void *);
3782a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *, const TaskState *, int);
3783a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *, const TaskState *);
3784edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *, const TaskState *);
3785edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
3786edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *);
3787edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *);
37889349b4f9SAndreas Färber static int fill_note_info(struct elf_note_info *, long, const CPUArchState *);
37899349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *, const CPUArchState *);
3790edf8e2afSMika Westerberg 
3791edf8e2afSMika Westerberg static int dump_write(int, const void *, size_t);
3792edf8e2afSMika Westerberg static int write_note(struct memelfnote *, int);
3793edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *, int);
3794edf8e2afSMika Westerberg 
3795edf8e2afSMika Westerberg #ifdef BSWAP_NEEDED
3796a2547a13SLaurent Desnogues static void bswap_prstatus(struct target_elf_prstatus *prstatus)
3797edf8e2afSMika Westerberg {
3798ca98ac83SPaolo Bonzini     prstatus->pr_info.si_signo = tswap32(prstatus->pr_info.si_signo);
3799ca98ac83SPaolo Bonzini     prstatus->pr_info.si_code = tswap32(prstatus->pr_info.si_code);
3800ca98ac83SPaolo Bonzini     prstatus->pr_info.si_errno = tswap32(prstatus->pr_info.si_errno);
3801edf8e2afSMika Westerberg     prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
3802ca98ac83SPaolo Bonzini     prstatus->pr_sigpend = tswapal(prstatus->pr_sigpend);
3803ca98ac83SPaolo Bonzini     prstatus->pr_sighold = tswapal(prstatus->pr_sighold);
3804edf8e2afSMika Westerberg     prstatus->pr_pid = tswap32(prstatus->pr_pid);
3805edf8e2afSMika Westerberg     prstatus->pr_ppid = tswap32(prstatus->pr_ppid);
3806edf8e2afSMika Westerberg     prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp);
3807edf8e2afSMika Westerberg     prstatus->pr_sid = tswap32(prstatus->pr_sid);
3808edf8e2afSMika Westerberg     /* cpu times are not filled, so we skip them */
3809edf8e2afSMika Westerberg     /* regs should be in correct format already */
3810edf8e2afSMika Westerberg     prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid);
3811edf8e2afSMika Westerberg }
3812edf8e2afSMika Westerberg 
3813a2547a13SLaurent Desnogues static void bswap_psinfo(struct target_elf_prpsinfo *psinfo)
3814edf8e2afSMika Westerberg {
3815ca98ac83SPaolo Bonzini     psinfo->pr_flag = tswapal(psinfo->pr_flag);
3816edf8e2afSMika Westerberg     psinfo->pr_uid = tswap16(psinfo->pr_uid);
3817edf8e2afSMika Westerberg     psinfo->pr_gid = tswap16(psinfo->pr_gid);
3818edf8e2afSMika Westerberg     psinfo->pr_pid = tswap32(psinfo->pr_pid);
3819edf8e2afSMika Westerberg     psinfo->pr_ppid = tswap32(psinfo->pr_ppid);
3820edf8e2afSMika Westerberg     psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp);
3821edf8e2afSMika Westerberg     psinfo->pr_sid = tswap32(psinfo->pr_sid);
3822edf8e2afSMika Westerberg }
3823991f8f0cSRichard Henderson 
3824991f8f0cSRichard Henderson static void bswap_note(struct elf_note *en)
3825991f8f0cSRichard Henderson {
3826991f8f0cSRichard Henderson     bswap32s(&en->n_namesz);
3827991f8f0cSRichard Henderson     bswap32s(&en->n_descsz);
3828991f8f0cSRichard Henderson     bswap32s(&en->n_type);
3829991f8f0cSRichard Henderson }
3830991f8f0cSRichard Henderson #else
3831991f8f0cSRichard Henderson static inline void bswap_prstatus(struct target_elf_prstatus *p) { }
3832991f8f0cSRichard Henderson static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {}
3833991f8f0cSRichard Henderson static inline void bswap_note(struct elf_note *en) { }
3834edf8e2afSMika Westerberg #endif /* BSWAP_NEEDED */
3835edf8e2afSMika Westerberg 
3836edf8e2afSMika Westerberg /*
3837edf8e2afSMika Westerberg  * Minimal support for linux memory regions.  These are needed
3838edf8e2afSMika Westerberg  * when we are finding out what memory exactly belongs to
3839edf8e2afSMika Westerberg  * emulated process.  No locks needed here, as long as
3840edf8e2afSMika Westerberg  * thread that received the signal is stopped.
3841edf8e2afSMika Westerberg  */
3842edf8e2afSMika Westerberg 
3843edf8e2afSMika Westerberg static struct mm_struct *vma_init(void)
3844edf8e2afSMika Westerberg {
3845edf8e2afSMika Westerberg     struct mm_struct *mm;
3846edf8e2afSMika Westerberg 
38477267c094SAnthony Liguori     if ((mm = g_malloc(sizeof (*mm))) == NULL)
3848edf8e2afSMika Westerberg         return (NULL);
3849edf8e2afSMika Westerberg 
3850edf8e2afSMika Westerberg     mm->mm_count = 0;
385172cf2d4fSBlue Swirl     QTAILQ_INIT(&mm->mm_mmap);
3852edf8e2afSMika Westerberg 
3853edf8e2afSMika Westerberg     return (mm);
3854edf8e2afSMika Westerberg }
3855edf8e2afSMika Westerberg 
3856edf8e2afSMika Westerberg static void vma_delete(struct mm_struct *mm)
3857edf8e2afSMika Westerberg {
3858edf8e2afSMika Westerberg     struct vm_area_struct *vma;
3859edf8e2afSMika Westerberg 
3860edf8e2afSMika Westerberg     while ((vma = vma_first(mm)) != NULL) {
386172cf2d4fSBlue Swirl         QTAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
38627267c094SAnthony Liguori         g_free(vma);
3863edf8e2afSMika Westerberg     }
38647267c094SAnthony Liguori     g_free(mm);
3865edf8e2afSMika Westerberg }
3866edf8e2afSMika Westerberg 
38671a1c4db9SMikhail Ilyin static int vma_add_mapping(struct mm_struct *mm, target_ulong start,
38681a1c4db9SMikhail Ilyin                            target_ulong end, abi_ulong flags)
3869edf8e2afSMika Westerberg {
3870edf8e2afSMika Westerberg     struct vm_area_struct *vma;
3871edf8e2afSMika Westerberg 
38727267c094SAnthony Liguori     if ((vma = g_malloc0(sizeof (*vma))) == NULL)
3873edf8e2afSMika Westerberg         return (-1);
3874edf8e2afSMika Westerberg 
3875edf8e2afSMika Westerberg     vma->vma_start = start;
3876edf8e2afSMika Westerberg     vma->vma_end = end;
3877edf8e2afSMika Westerberg     vma->vma_flags = flags;
3878edf8e2afSMika Westerberg 
387972cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
3880edf8e2afSMika Westerberg     mm->mm_count++;
3881edf8e2afSMika Westerberg 
3882edf8e2afSMika Westerberg     return (0);
3883edf8e2afSMika Westerberg }
3884edf8e2afSMika Westerberg 
3885edf8e2afSMika Westerberg static struct vm_area_struct *vma_first(const struct mm_struct *mm)
3886edf8e2afSMika Westerberg {
388772cf2d4fSBlue Swirl     return (QTAILQ_FIRST(&mm->mm_mmap));
3888edf8e2afSMika Westerberg }
3889edf8e2afSMika Westerberg 
3890edf8e2afSMika Westerberg static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
3891edf8e2afSMika Westerberg {
389272cf2d4fSBlue Swirl     return (QTAILQ_NEXT(vma, vma_link));
3893edf8e2afSMika Westerberg }
3894edf8e2afSMika Westerberg 
3895edf8e2afSMika Westerberg static int vma_get_mapping_count(const struct mm_struct *mm)
3896edf8e2afSMika Westerberg {
3897edf8e2afSMika Westerberg     return (mm->mm_count);
3898edf8e2afSMika Westerberg }
3899edf8e2afSMika Westerberg 
3900edf8e2afSMika Westerberg /*
3901edf8e2afSMika Westerberg  * Calculate file (dump) size of given memory region.
3902edf8e2afSMika Westerberg  */
3903edf8e2afSMika Westerberg static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
3904edf8e2afSMika Westerberg {
3905edf8e2afSMika Westerberg     /* if we cannot even read the first page, skip it */
3906c7169b02SRichard Henderson     if (!access_ok_untagged(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
3907edf8e2afSMika Westerberg         return (0);
3908edf8e2afSMika Westerberg 
3909edf8e2afSMika Westerberg     /*
3910edf8e2afSMika Westerberg      * Usually we don't dump executable pages as they contain
3911edf8e2afSMika Westerberg      * non-writable code that debugger can read directly from
3912edf8e2afSMika Westerberg      * target library etc.  However, thread stacks are marked
3913edf8e2afSMika Westerberg      * also executable so we read in first page of given region
3914edf8e2afSMika Westerberg      * and check whether it contains elf header.  If there is
3915edf8e2afSMika Westerberg      * no elf header, we dump it.
3916edf8e2afSMika Westerberg      */
3917edf8e2afSMika Westerberg     if (vma->vma_flags & PROT_EXEC) {
3918edf8e2afSMika Westerberg         char page[TARGET_PAGE_SIZE];
3919edf8e2afSMika Westerberg 
3920022625a8SPeter Maydell         if (copy_from_user(page, vma->vma_start, sizeof (page))) {
3921022625a8SPeter Maydell             return 0;
3922022625a8SPeter Maydell         }
3923edf8e2afSMika Westerberg         if ((page[EI_MAG0] == ELFMAG0) &&
3924edf8e2afSMika Westerberg             (page[EI_MAG1] == ELFMAG1) &&
3925edf8e2afSMika Westerberg             (page[EI_MAG2] == ELFMAG2) &&
3926edf8e2afSMika Westerberg             (page[EI_MAG3] == ELFMAG3)) {
3927edf8e2afSMika Westerberg             /*
3928edf8e2afSMika Westerberg              * Mappings are possibly from ELF binary.  Don't dump
3929edf8e2afSMika Westerberg              * them.
3930edf8e2afSMika Westerberg              */
3931edf8e2afSMika Westerberg             return (0);
3932edf8e2afSMika Westerberg         }
3933edf8e2afSMika Westerberg     }
3934edf8e2afSMika Westerberg 
3935edf8e2afSMika Westerberg     return (vma->vma_end - vma->vma_start);
3936edf8e2afSMika Westerberg }
3937edf8e2afSMika Westerberg 
39381a1c4db9SMikhail Ilyin static int vma_walker(void *priv, target_ulong start, target_ulong end,
3939edf8e2afSMika Westerberg                       unsigned long flags)
3940edf8e2afSMika Westerberg {
3941edf8e2afSMika Westerberg     struct mm_struct *mm = (struct mm_struct *)priv;
3942edf8e2afSMika Westerberg 
3943edf8e2afSMika Westerberg     vma_add_mapping(mm, start, end, flags);
3944edf8e2afSMika Westerberg     return (0);
3945edf8e2afSMika Westerberg }
3946edf8e2afSMika Westerberg 
3947edf8e2afSMika Westerberg static void fill_note(struct memelfnote *note, const char *name, int type,
3948edf8e2afSMika Westerberg                       unsigned int sz, void *data)
3949edf8e2afSMika Westerberg {
3950edf8e2afSMika Westerberg     unsigned int namesz;
3951edf8e2afSMika Westerberg 
3952edf8e2afSMika Westerberg     namesz = strlen(name) + 1;
3953edf8e2afSMika Westerberg     note->name = name;
3954edf8e2afSMika Westerberg     note->namesz = namesz;
3955edf8e2afSMika Westerberg     note->namesz_rounded = roundup(namesz, sizeof (int32_t));
3956edf8e2afSMika Westerberg     note->type = type;
395780f5ce75SLaurent Vivier     note->datasz = sz;
395880f5ce75SLaurent Vivier     note->datasz_rounded = roundup(sz, sizeof (int32_t));
395980f5ce75SLaurent Vivier 
3960edf8e2afSMika Westerberg     note->data = data;
3961edf8e2afSMika Westerberg 
3962edf8e2afSMika Westerberg     /*
3963edf8e2afSMika Westerberg      * We calculate rounded up note size here as specified by
3964edf8e2afSMika Westerberg      * ELF document.
3965edf8e2afSMika Westerberg      */
3966edf8e2afSMika Westerberg     note->notesz = sizeof (struct elf_note) +
396780f5ce75SLaurent Vivier         note->namesz_rounded + note->datasz_rounded;
3968edf8e2afSMika Westerberg }
3969edf8e2afSMika Westerberg 
3970edf8e2afSMika Westerberg static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
3971edf8e2afSMika Westerberg                             uint32_t flags)
3972edf8e2afSMika Westerberg {
3973edf8e2afSMika Westerberg     (void) memset(elf, 0, sizeof(*elf));
3974edf8e2afSMika Westerberg 
3975edf8e2afSMika Westerberg     (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
3976edf8e2afSMika Westerberg     elf->e_ident[EI_CLASS] = ELF_CLASS;
3977edf8e2afSMika Westerberg     elf->e_ident[EI_DATA] = ELF_DATA;
3978edf8e2afSMika Westerberg     elf->e_ident[EI_VERSION] = EV_CURRENT;
3979edf8e2afSMika Westerberg     elf->e_ident[EI_OSABI] = ELF_OSABI;
3980edf8e2afSMika Westerberg 
3981edf8e2afSMika Westerberg     elf->e_type = ET_CORE;
3982edf8e2afSMika Westerberg     elf->e_machine = machine;
3983edf8e2afSMika Westerberg     elf->e_version = EV_CURRENT;
3984edf8e2afSMika Westerberg     elf->e_phoff = sizeof(struct elfhdr);
3985edf8e2afSMika Westerberg     elf->e_flags = flags;
3986edf8e2afSMika Westerberg     elf->e_ehsize = sizeof(struct elfhdr);
3987edf8e2afSMika Westerberg     elf->e_phentsize = sizeof(struct elf_phdr);
3988edf8e2afSMika Westerberg     elf->e_phnum = segs;
3989edf8e2afSMika Westerberg 
3990edf8e2afSMika Westerberg     bswap_ehdr(elf);
3991edf8e2afSMika Westerberg }
3992edf8e2afSMika Westerberg 
3993edf8e2afSMika Westerberg static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
3994edf8e2afSMika Westerberg {
3995edf8e2afSMika Westerberg     phdr->p_type = PT_NOTE;
3996edf8e2afSMika Westerberg     phdr->p_offset = offset;
3997edf8e2afSMika Westerberg     phdr->p_vaddr = 0;
3998edf8e2afSMika Westerberg     phdr->p_paddr = 0;
3999edf8e2afSMika Westerberg     phdr->p_filesz = sz;
4000edf8e2afSMika Westerberg     phdr->p_memsz = 0;
4001edf8e2afSMika Westerberg     phdr->p_flags = 0;
4002edf8e2afSMika Westerberg     phdr->p_align = 0;
4003edf8e2afSMika Westerberg 
4004991f8f0cSRichard Henderson     bswap_phdr(phdr, 1);
4005edf8e2afSMika Westerberg }
4006edf8e2afSMika Westerberg 
4007edf8e2afSMika Westerberg static size_t note_size(const struct memelfnote *note)
4008edf8e2afSMika Westerberg {
4009edf8e2afSMika Westerberg     return (note->notesz);
4010edf8e2afSMika Westerberg }
4011edf8e2afSMika Westerberg 
4012a2547a13SLaurent Desnogues static void fill_prstatus(struct target_elf_prstatus *prstatus,
4013edf8e2afSMika Westerberg                           const TaskState *ts, int signr)
4014edf8e2afSMika Westerberg {
4015edf8e2afSMika Westerberg     (void) memset(prstatus, 0, sizeof (*prstatus));
4016edf8e2afSMika Westerberg     prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
4017edf8e2afSMika Westerberg     prstatus->pr_pid = ts->ts_tid;
4018edf8e2afSMika Westerberg     prstatus->pr_ppid = getppid();
4019edf8e2afSMika Westerberg     prstatus->pr_pgrp = getpgrp();
4020edf8e2afSMika Westerberg     prstatus->pr_sid = getsid(0);
4021edf8e2afSMika Westerberg 
4022edf8e2afSMika Westerberg     bswap_prstatus(prstatus);
4023edf8e2afSMika Westerberg }
4024edf8e2afSMika Westerberg 
4025a2547a13SLaurent Desnogues static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
4026edf8e2afSMika Westerberg {
4027900cfbcaSJim Meyering     char *base_filename;
4028edf8e2afSMika Westerberg     unsigned int i, len;
4029edf8e2afSMika Westerberg 
4030edf8e2afSMika Westerberg     (void) memset(psinfo, 0, sizeof (*psinfo));
4031edf8e2afSMika Westerberg 
40325f779a3aSIlya Leoshkevich     len = ts->info->env_strings - ts->info->arg_strings;
4033edf8e2afSMika Westerberg     if (len >= ELF_PRARGSZ)
4034edf8e2afSMika Westerberg         len = ELF_PRARGSZ - 1;
40355f779a3aSIlya Leoshkevich     if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_strings, len)) {
4036edf8e2afSMika Westerberg         return -EFAULT;
40375f779a3aSIlya Leoshkevich     }
4038edf8e2afSMika Westerberg     for (i = 0; i < len; i++)
4039edf8e2afSMika Westerberg         if (psinfo->pr_psargs[i] == 0)
4040edf8e2afSMika Westerberg             psinfo->pr_psargs[i] = ' ';
4041edf8e2afSMika Westerberg     psinfo->pr_psargs[len] = 0;
4042edf8e2afSMika Westerberg 
4043edf8e2afSMika Westerberg     psinfo->pr_pid = getpid();
4044edf8e2afSMika Westerberg     psinfo->pr_ppid = getppid();
4045edf8e2afSMika Westerberg     psinfo->pr_pgrp = getpgrp();
4046edf8e2afSMika Westerberg     psinfo->pr_sid = getsid(0);
4047edf8e2afSMika Westerberg     psinfo->pr_uid = getuid();
4048edf8e2afSMika Westerberg     psinfo->pr_gid = getgid();
4049edf8e2afSMika Westerberg 
4050900cfbcaSJim Meyering     base_filename = g_path_get_basename(ts->bprm->filename);
4051900cfbcaSJim Meyering     /*
4052900cfbcaSJim Meyering      * Using strncpy here is fine: at max-length,
4053900cfbcaSJim Meyering      * this field is not NUL-terminated.
4054900cfbcaSJim Meyering      */
4055edf8e2afSMika Westerberg     (void) strncpy(psinfo->pr_fname, base_filename,
4056edf8e2afSMika Westerberg                    sizeof(psinfo->pr_fname));
4057edf8e2afSMika Westerberg 
4058900cfbcaSJim Meyering     g_free(base_filename);
4059edf8e2afSMika Westerberg     bswap_psinfo(psinfo);
4060edf8e2afSMika Westerberg     return (0);
4061edf8e2afSMika Westerberg }
4062edf8e2afSMika Westerberg 
4063edf8e2afSMika Westerberg static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
4064edf8e2afSMika Westerberg {
4065edf8e2afSMika Westerberg     elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
4066edf8e2afSMika Westerberg     elf_addr_t orig_auxv = auxv;
4067edf8e2afSMika Westerberg     void *ptr;
4068125b0f55SAlexander Graf     int len = ts->info->auxv_len;
4069edf8e2afSMika Westerberg 
4070edf8e2afSMika Westerberg     /*
4071edf8e2afSMika Westerberg      * Auxiliary vector is stored in target process stack.  It contains
4072edf8e2afSMika Westerberg      * {type, value} pairs that we need to dump into note.  This is not
4073edf8e2afSMika Westerberg      * strictly necessary but we do it here for sake of completeness.
4074edf8e2afSMika Westerberg      */
4075edf8e2afSMika Westerberg 
4076edf8e2afSMika Westerberg     /* read in whole auxv vector and copy it to memelfnote */
4077edf8e2afSMika Westerberg     ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
4078edf8e2afSMika Westerberg     if (ptr != NULL) {
4079edf8e2afSMika Westerberg         fill_note(note, "CORE", NT_AUXV, len, ptr);
4080edf8e2afSMika Westerberg         unlock_user(ptr, auxv, len);
4081edf8e2afSMika Westerberg     }
4082edf8e2afSMika Westerberg }
4083edf8e2afSMika Westerberg 
4084edf8e2afSMika Westerberg /*
4085edf8e2afSMika Westerberg  * Constructs name of coredump file.  We have following convention
4086edf8e2afSMika Westerberg  * for the name:
4087edf8e2afSMika Westerberg  *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
4088edf8e2afSMika Westerberg  *
408968af19adSDaniel P. Berrangé  * Returns the filename
4090edf8e2afSMika Westerberg  */
409168af19adSDaniel P. Berrangé static char *core_dump_filename(const TaskState *ts)
4092edf8e2afSMika Westerberg {
409368af19adSDaniel P. Berrangé     g_autoptr(GDateTime) now = g_date_time_new_now_local();
409468af19adSDaniel P. Berrangé     g_autofree char *nowstr = g_date_time_format(now, "%Y%m%d-%H%M%S");
409568af19adSDaniel P. Berrangé     g_autofree char *base_filename = g_path_get_basename(ts->bprm->filename);
4096edf8e2afSMika Westerberg 
409768af19adSDaniel P. Berrangé     return g_strdup_printf("qemu_%s_%s_%d.core",
409868af19adSDaniel P. Berrangé                            base_filename, nowstr, (int)getpid());
4099edf8e2afSMika Westerberg }
4100edf8e2afSMika Westerberg 
4101edf8e2afSMika Westerberg static int dump_write(int fd, const void *ptr, size_t size)
4102edf8e2afSMika Westerberg {
4103edf8e2afSMika Westerberg     const char *bufp = (const char *)ptr;
4104edf8e2afSMika Westerberg     ssize_t bytes_written, bytes_left;
4105edf8e2afSMika Westerberg     struct rlimit dumpsize;
4106edf8e2afSMika Westerberg     off_t pos;
4107edf8e2afSMika Westerberg 
4108edf8e2afSMika Westerberg     bytes_written = 0;
4109edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
4110edf8e2afSMika Westerberg     if ((pos = lseek(fd, 0, SEEK_CUR))==-1) {
4111edf8e2afSMika Westerberg         if (errno == ESPIPE) { /* not a seekable stream */
4112edf8e2afSMika Westerberg             bytes_left = size;
4113edf8e2afSMika Westerberg         } else {
4114edf8e2afSMika Westerberg             return pos;
4115edf8e2afSMika Westerberg         }
4116edf8e2afSMika Westerberg     } else {
4117edf8e2afSMika Westerberg         if (dumpsize.rlim_cur <= pos) {
4118edf8e2afSMika Westerberg             return -1;
4119edf8e2afSMika Westerberg         } else if (dumpsize.rlim_cur == RLIM_INFINITY) {
4120edf8e2afSMika Westerberg             bytes_left = size;
4121edf8e2afSMika Westerberg         } else {
4122edf8e2afSMika Westerberg             size_t limit_left=dumpsize.rlim_cur - pos;
4123edf8e2afSMika Westerberg             bytes_left = limit_left >= size ? size : limit_left ;
4124edf8e2afSMika Westerberg         }
4125edf8e2afSMika Westerberg     }
4126edf8e2afSMika Westerberg 
4127edf8e2afSMika Westerberg     /*
4128edf8e2afSMika Westerberg      * In normal conditions, single write(2) should do but
4129edf8e2afSMika Westerberg      * in case of socket etc. this mechanism is more portable.
4130edf8e2afSMika Westerberg      */
4131edf8e2afSMika Westerberg     do {
4132edf8e2afSMika Westerberg         bytes_written = write(fd, bufp, bytes_left);
4133edf8e2afSMika Westerberg         if (bytes_written < 0) {
4134edf8e2afSMika Westerberg             if (errno == EINTR)
4135edf8e2afSMika Westerberg                 continue;
4136edf8e2afSMika Westerberg             return (-1);
4137edf8e2afSMika Westerberg         } else if (bytes_written == 0) { /* eof */
4138edf8e2afSMika Westerberg             return (-1);
4139edf8e2afSMika Westerberg         }
4140edf8e2afSMika Westerberg         bufp += bytes_written;
4141edf8e2afSMika Westerberg         bytes_left -= bytes_written;
4142edf8e2afSMika Westerberg     } while (bytes_left > 0);
4143edf8e2afSMika Westerberg 
4144edf8e2afSMika Westerberg     return (0);
4145edf8e2afSMika Westerberg }
4146edf8e2afSMika Westerberg 
4147edf8e2afSMika Westerberg static int write_note(struct memelfnote *men, int fd)
4148edf8e2afSMika Westerberg {
4149edf8e2afSMika Westerberg     struct elf_note en;
4150edf8e2afSMika Westerberg 
4151edf8e2afSMika Westerberg     en.n_namesz = men->namesz;
4152edf8e2afSMika Westerberg     en.n_type = men->type;
4153edf8e2afSMika Westerberg     en.n_descsz = men->datasz;
4154edf8e2afSMika Westerberg 
4155edf8e2afSMika Westerberg     bswap_note(&en);
4156edf8e2afSMika Westerberg 
4157edf8e2afSMika Westerberg     if (dump_write(fd, &en, sizeof(en)) != 0)
4158edf8e2afSMika Westerberg         return (-1);
4159edf8e2afSMika Westerberg     if (dump_write(fd, men->name, men->namesz_rounded) != 0)
4160edf8e2afSMika Westerberg         return (-1);
416180f5ce75SLaurent Vivier     if (dump_write(fd, men->data, men->datasz_rounded) != 0)
4162edf8e2afSMika Westerberg         return (-1);
4163edf8e2afSMika Westerberg 
4164edf8e2afSMika Westerberg     return (0);
4165edf8e2afSMika Westerberg }
4166edf8e2afSMika Westerberg 
41679349b4f9SAndreas Färber static void fill_thread_info(struct elf_note_info *info, const CPUArchState *env)
4168edf8e2afSMika Westerberg {
416929a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
41700429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4171edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4172edf8e2afSMika Westerberg 
41737267c094SAnthony Liguori     ets = g_malloc0(sizeof (*ets));
4174edf8e2afSMika Westerberg     ets->num_notes = 1; /* only prstatus is dumped */
4175edf8e2afSMika Westerberg     fill_prstatus(&ets->prstatus, ts, 0);
4176edf8e2afSMika Westerberg     elf_core_copy_regs(&ets->prstatus.pr_reg, env);
4177edf8e2afSMika Westerberg     fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
4178edf8e2afSMika Westerberg               &ets->prstatus);
4179edf8e2afSMika Westerberg 
418072cf2d4fSBlue Swirl     QTAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
4181edf8e2afSMika Westerberg 
4182edf8e2afSMika Westerberg     info->notes_size += note_size(&ets->notes[0]);
4183edf8e2afSMika Westerberg }
4184edf8e2afSMika Westerberg 
41856afafa86SPeter Maydell static void init_note_info(struct elf_note_info *info)
41866afafa86SPeter Maydell {
41876afafa86SPeter Maydell     /* Initialize the elf_note_info structure so that it is at
41886afafa86SPeter Maydell      * least safe to call free_note_info() on it. Must be
41896afafa86SPeter Maydell      * called before calling fill_note_info().
41906afafa86SPeter Maydell      */
41916afafa86SPeter Maydell     memset(info, 0, sizeof (*info));
41926afafa86SPeter Maydell     QTAILQ_INIT(&info->thread_list);
41936afafa86SPeter Maydell }
41946afafa86SPeter Maydell 
4195edf8e2afSMika Westerberg static int fill_note_info(struct elf_note_info *info,
41969349b4f9SAndreas Färber                           long signr, const CPUArchState *env)
4197edf8e2afSMika Westerberg {
4198edf8e2afSMika Westerberg #define NUMNOTES 3
419929a0af61SRichard Henderson     CPUState *cpu = env_cpu((CPUArchState *)env);
42000429a971SAndreas Färber     TaskState *ts = (TaskState *)cpu->opaque;
4201edf8e2afSMika Westerberg     int i;
4202edf8e2afSMika Westerberg 
4203c78d65e8SMarkus Armbruster     info->notes = g_new0(struct memelfnote, NUMNOTES);
4204edf8e2afSMika Westerberg     if (info->notes == NULL)
4205edf8e2afSMika Westerberg         return (-ENOMEM);
42067267c094SAnthony Liguori     info->prstatus = g_malloc0(sizeof (*info->prstatus));
4207edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4208edf8e2afSMika Westerberg         return (-ENOMEM);
42097267c094SAnthony Liguori     info->psinfo = g_malloc0(sizeof (*info->psinfo));
4210edf8e2afSMika Westerberg     if (info->prstatus == NULL)
4211edf8e2afSMika Westerberg         return (-ENOMEM);
4212edf8e2afSMika Westerberg 
4213edf8e2afSMika Westerberg     /*
4214edf8e2afSMika Westerberg      * First fill in status (and registers) of current thread
4215edf8e2afSMika Westerberg      * including process info & aux vector.
4216edf8e2afSMika Westerberg      */
4217edf8e2afSMika Westerberg     fill_prstatus(info->prstatus, ts, signr);
4218edf8e2afSMika Westerberg     elf_core_copy_regs(&info->prstatus->pr_reg, env);
4219edf8e2afSMika Westerberg     fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
4220edf8e2afSMika Westerberg               sizeof (*info->prstatus), info->prstatus);
4221edf8e2afSMika Westerberg     fill_psinfo(info->psinfo, ts);
4222edf8e2afSMika Westerberg     fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
4223edf8e2afSMika Westerberg               sizeof (*info->psinfo), info->psinfo);
4224edf8e2afSMika Westerberg     fill_auxv_note(&info->notes[2], ts);
4225edf8e2afSMika Westerberg     info->numnote = 3;
4226edf8e2afSMika Westerberg 
4227edf8e2afSMika Westerberg     info->notes_size = 0;
4228edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4229edf8e2afSMika Westerberg         info->notes_size += note_size(&info->notes[i]);
4230edf8e2afSMika Westerberg 
4231edf8e2afSMika Westerberg     /* read and fill status of all threads */
4232370ed600SJamie Iles     WITH_QEMU_LOCK_GUARD(&qemu_cpu_list_lock) {
4233bdc44640SAndreas Färber         CPU_FOREACH(cpu) {
4234a2247f8eSAndreas Färber             if (cpu == thread_cpu) {
4235edf8e2afSMika Westerberg                 continue;
4236182735efSAndreas Färber             }
42372f6f4290SPhilippe Mathieu-Daudé             fill_thread_info(info, cpu->env_ptr);
4238edf8e2afSMika Westerberg         }
4239370ed600SJamie Iles     }
4240edf8e2afSMika Westerberg 
4241edf8e2afSMika Westerberg     return (0);
4242edf8e2afSMika Westerberg }
4243edf8e2afSMika Westerberg 
4244edf8e2afSMika Westerberg static void free_note_info(struct elf_note_info *info)
4245edf8e2afSMika Westerberg {
4246edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4247edf8e2afSMika Westerberg 
424872cf2d4fSBlue Swirl     while (!QTAILQ_EMPTY(&info->thread_list)) {
424972cf2d4fSBlue Swirl         ets = QTAILQ_FIRST(&info->thread_list);
425072cf2d4fSBlue Swirl         QTAILQ_REMOVE(&info->thread_list, ets, ets_link);
42517267c094SAnthony Liguori         g_free(ets);
4252edf8e2afSMika Westerberg     }
4253edf8e2afSMika Westerberg 
42547267c094SAnthony Liguori     g_free(info->prstatus);
42557267c094SAnthony Liguori     g_free(info->psinfo);
42567267c094SAnthony Liguori     g_free(info->notes);
4257edf8e2afSMika Westerberg }
4258edf8e2afSMika Westerberg 
4259edf8e2afSMika Westerberg static int write_note_info(struct elf_note_info *info, int fd)
4260edf8e2afSMika Westerberg {
4261edf8e2afSMika Westerberg     struct elf_thread_status *ets;
4262edf8e2afSMika Westerberg     int i, error = 0;
4263edf8e2afSMika Westerberg 
4264edf8e2afSMika Westerberg     /* write prstatus, psinfo and auxv for current thread */
4265edf8e2afSMika Westerberg     for (i = 0; i < info->numnote; i++)
4266edf8e2afSMika Westerberg         if ((error = write_note(&info->notes[i], fd)) != 0)
4267edf8e2afSMika Westerberg             return (error);
4268edf8e2afSMika Westerberg 
4269edf8e2afSMika Westerberg     /* write prstatus for each thread */
427052a53afeSEmilio G. Cota     QTAILQ_FOREACH(ets, &info->thread_list, ets_link) {
4271edf8e2afSMika Westerberg         if ((error = write_note(&ets->notes[0], fd)) != 0)
4272edf8e2afSMika Westerberg             return (error);
4273edf8e2afSMika Westerberg     }
4274edf8e2afSMika Westerberg 
4275edf8e2afSMika Westerberg     return (0);
4276edf8e2afSMika Westerberg }
4277edf8e2afSMika Westerberg 
4278edf8e2afSMika Westerberg /*
4279edf8e2afSMika Westerberg  * Write out ELF coredump.
4280edf8e2afSMika Westerberg  *
4281edf8e2afSMika Westerberg  * See documentation of ELF object file format in:
4282edf8e2afSMika Westerberg  * http://www.caldera.com/developers/devspecs/gabi41.pdf
4283edf8e2afSMika Westerberg  *
4284edf8e2afSMika Westerberg  * Coredump format in linux is following:
4285edf8e2afSMika Westerberg  *
4286edf8e2afSMika Westerberg  * 0   +----------------------+         \
4287edf8e2afSMika Westerberg  *     | ELF header           | ET_CORE  |
4288edf8e2afSMika Westerberg  *     +----------------------+          |
4289edf8e2afSMika Westerberg  *     | ELF program headers  |          |--- headers
4290edf8e2afSMika Westerberg  *     | - NOTE section       |          |
4291edf8e2afSMika Westerberg  *     | - PT_LOAD sections   |          |
4292edf8e2afSMika Westerberg  *     +----------------------+         /
4293edf8e2afSMika Westerberg  *     | NOTEs:               |
4294edf8e2afSMika Westerberg  *     | - NT_PRSTATUS        |
4295edf8e2afSMika Westerberg  *     | - NT_PRSINFO         |
4296edf8e2afSMika Westerberg  *     | - NT_AUXV            |
4297edf8e2afSMika Westerberg  *     +----------------------+ <-- aligned to target page
4298edf8e2afSMika Westerberg  *     | Process memory dump  |
4299edf8e2afSMika Westerberg  *     :                      :
4300edf8e2afSMika Westerberg  *     .                      .
4301edf8e2afSMika Westerberg  *     :                      :
4302edf8e2afSMika Westerberg  *     |                      |
4303edf8e2afSMika Westerberg  *     +----------------------+
4304edf8e2afSMika Westerberg  *
4305edf8e2afSMika Westerberg  * NT_PRSTATUS -> struct elf_prstatus (per thread)
4306edf8e2afSMika Westerberg  * NT_PRSINFO  -> struct elf_prpsinfo
4307edf8e2afSMika Westerberg  * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
4308edf8e2afSMika Westerberg  *
4309edf8e2afSMika Westerberg  * Format follows System V format as close as possible.  Current
4310edf8e2afSMika Westerberg  * version limitations are as follows:
4311edf8e2afSMika Westerberg  *     - no floating point registers are dumped
4312edf8e2afSMika Westerberg  *
4313edf8e2afSMika Westerberg  * Function returns 0 in case of success, negative errno otherwise.
4314edf8e2afSMika Westerberg  *
4315edf8e2afSMika Westerberg  * TODO: make this work also during runtime: it should be
4316edf8e2afSMika Westerberg  * possible to force coredump from running process and then
4317edf8e2afSMika Westerberg  * continue processing.  For example qemu could set up SIGUSR2
4318edf8e2afSMika Westerberg  * handler (provided that target process haven't registered
4319edf8e2afSMika Westerberg  * handler for that) that does the dump when signal is received.
4320edf8e2afSMika Westerberg  */
43219349b4f9SAndreas Färber static int elf_core_dump(int signr, const CPUArchState *env)
4322edf8e2afSMika Westerberg {
432329a0af61SRichard Henderson     const CPUState *cpu = env_cpu((CPUArchState *)env);
43240429a971SAndreas Färber     const TaskState *ts = (const TaskState *)cpu->opaque;
4325edf8e2afSMika Westerberg     struct vm_area_struct *vma = NULL;
432668af19adSDaniel P. Berrangé     g_autofree char *corefile = NULL;
4327edf8e2afSMika Westerberg     struct elf_note_info info;
4328edf8e2afSMika Westerberg     struct elfhdr elf;
4329edf8e2afSMika Westerberg     struct elf_phdr phdr;
4330edf8e2afSMika Westerberg     struct rlimit dumpsize;
4331edf8e2afSMika Westerberg     struct mm_struct *mm = NULL;
4332edf8e2afSMika Westerberg     off_t offset = 0, data_offset = 0;
4333edf8e2afSMika Westerberg     int segs = 0;
4334edf8e2afSMika Westerberg     int fd = -1;
4335edf8e2afSMika Westerberg 
43366afafa86SPeter Maydell     init_note_info(&info);
43376afafa86SPeter Maydell 
4338edf8e2afSMika Westerberg     errno = 0;
4339edf8e2afSMika Westerberg     getrlimit(RLIMIT_CORE, &dumpsize);
4340edf8e2afSMika Westerberg     if (dumpsize.rlim_cur == 0)
4341edf8e2afSMika Westerberg         return 0;
4342edf8e2afSMika Westerberg 
434368af19adSDaniel P. Berrangé     corefile = core_dump_filename(ts);
4344edf8e2afSMika Westerberg 
4345edf8e2afSMika Westerberg     if ((fd = open(corefile, O_WRONLY | O_CREAT,
4346edf8e2afSMika Westerberg                    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
4347edf8e2afSMika Westerberg         return (-errno);
4348edf8e2afSMika Westerberg 
4349edf8e2afSMika Westerberg     /*
4350edf8e2afSMika Westerberg      * Walk through target process memory mappings and
4351edf8e2afSMika Westerberg      * set up structure containing this information.  After
4352edf8e2afSMika Westerberg      * this point vma_xxx functions can be used.
4353edf8e2afSMika Westerberg      */
4354edf8e2afSMika Westerberg     if ((mm = vma_init()) == NULL)
4355edf8e2afSMika Westerberg         goto out;
4356edf8e2afSMika Westerberg 
4357edf8e2afSMika Westerberg     walk_memory_regions(mm, vma_walker);
4358edf8e2afSMika Westerberg     segs = vma_get_mapping_count(mm);
4359edf8e2afSMika Westerberg 
4360edf8e2afSMika Westerberg     /*
4361edf8e2afSMika Westerberg      * Construct valid coredump ELF header.  We also
4362edf8e2afSMika Westerberg      * add one more segment for notes.
4363edf8e2afSMika Westerberg      */
4364edf8e2afSMika Westerberg     fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
4365edf8e2afSMika Westerberg     if (dump_write(fd, &elf, sizeof (elf)) != 0)
4366edf8e2afSMika Westerberg         goto out;
4367edf8e2afSMika Westerberg 
4368b6af0975SDaniel P. Berrange     /* fill in the in-memory version of notes */
4369edf8e2afSMika Westerberg     if (fill_note_info(&info, signr, env) < 0)
4370edf8e2afSMika Westerberg         goto out;
4371edf8e2afSMika Westerberg 
4372edf8e2afSMika Westerberg     offset += sizeof (elf);                             /* elf header */
4373edf8e2afSMika Westerberg     offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
4374edf8e2afSMika Westerberg 
4375edf8e2afSMika Westerberg     /* write out notes program header */
4376edf8e2afSMika Westerberg     fill_elf_note_phdr(&phdr, info.notes_size, offset);
4377edf8e2afSMika Westerberg 
4378edf8e2afSMika Westerberg     offset += info.notes_size;
4379edf8e2afSMika Westerberg     if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
4380edf8e2afSMika Westerberg         goto out;
4381edf8e2afSMika Westerberg 
4382edf8e2afSMika Westerberg     /*
4383edf8e2afSMika Westerberg      * ELF specification wants data to start at page boundary so
4384edf8e2afSMika Westerberg      * we align it here.
4385edf8e2afSMika Westerberg      */
438680f5ce75SLaurent Vivier     data_offset = offset = roundup(offset, ELF_EXEC_PAGESIZE);
4387edf8e2afSMika Westerberg 
4388edf8e2afSMika Westerberg     /*
4389edf8e2afSMika Westerberg      * Write program headers for memory regions mapped in
4390edf8e2afSMika Westerberg      * the target process.
4391edf8e2afSMika Westerberg      */
4392edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4393edf8e2afSMika Westerberg         (void) memset(&phdr, 0, sizeof (phdr));
4394edf8e2afSMika Westerberg 
4395edf8e2afSMika Westerberg         phdr.p_type = PT_LOAD;
4396edf8e2afSMika Westerberg         phdr.p_offset = offset;
4397edf8e2afSMika Westerberg         phdr.p_vaddr = vma->vma_start;
4398edf8e2afSMika Westerberg         phdr.p_paddr = 0;
4399edf8e2afSMika Westerberg         phdr.p_filesz = vma_dump_size(vma);
4400edf8e2afSMika Westerberg         offset += phdr.p_filesz;
4401edf8e2afSMika Westerberg         phdr.p_memsz = vma->vma_end - vma->vma_start;
4402edf8e2afSMika Westerberg         phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
4403edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_WRITE)
4404edf8e2afSMika Westerberg             phdr.p_flags |= PF_W;
4405edf8e2afSMika Westerberg         if (vma->vma_flags & PROT_EXEC)
4406edf8e2afSMika Westerberg             phdr.p_flags |= PF_X;
4407edf8e2afSMika Westerberg         phdr.p_align = ELF_EXEC_PAGESIZE;
4408edf8e2afSMika Westerberg 
440980f5ce75SLaurent Vivier         bswap_phdr(&phdr, 1);
4410772034b6SPeter Maydell         if (dump_write(fd, &phdr, sizeof(phdr)) != 0) {
4411772034b6SPeter Maydell             goto out;
4412772034b6SPeter Maydell         }
4413edf8e2afSMika Westerberg     }
4414edf8e2afSMika Westerberg 
4415edf8e2afSMika Westerberg     /*
4416edf8e2afSMika Westerberg      * Next we write notes just after program headers.  No
4417edf8e2afSMika Westerberg      * alignment needed here.
4418edf8e2afSMika Westerberg      */
4419edf8e2afSMika Westerberg     if (write_note_info(&info, fd) < 0)
4420edf8e2afSMika Westerberg         goto out;
4421edf8e2afSMika Westerberg 
4422edf8e2afSMika Westerberg     /* align data to page boundary */
4423edf8e2afSMika Westerberg     if (lseek(fd, data_offset, SEEK_SET) != data_offset)
4424edf8e2afSMika Westerberg         goto out;
4425edf8e2afSMika Westerberg 
4426edf8e2afSMika Westerberg     /*
4427edf8e2afSMika Westerberg      * Finally we can dump process memory into corefile as well.
4428edf8e2afSMika Westerberg      */
4429edf8e2afSMika Westerberg     for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
4430edf8e2afSMika Westerberg         abi_ulong addr;
4431edf8e2afSMika Westerberg         abi_ulong end;
4432edf8e2afSMika Westerberg 
4433edf8e2afSMika Westerberg         end = vma->vma_start + vma_dump_size(vma);
4434edf8e2afSMika Westerberg 
4435edf8e2afSMika Westerberg         for (addr = vma->vma_start; addr < end;
4436edf8e2afSMika Westerberg              addr += TARGET_PAGE_SIZE) {
4437edf8e2afSMika Westerberg             char page[TARGET_PAGE_SIZE];
4438edf8e2afSMika Westerberg             int error;
4439edf8e2afSMika Westerberg 
4440edf8e2afSMika Westerberg             /*
4441edf8e2afSMika Westerberg              *  Read in page from target process memory and
4442edf8e2afSMika Westerberg              *  write it to coredump file.
4443edf8e2afSMika Westerberg              */
4444edf8e2afSMika Westerberg             error = copy_from_user(page, addr, sizeof (page));
4445edf8e2afSMika Westerberg             if (error != 0) {
444649995e17SAurelien Jarno                 (void) fprintf(stderr, "unable to dump " TARGET_ABI_FMT_lx "\n",
4447edf8e2afSMika Westerberg                                addr);
4448edf8e2afSMika Westerberg                 errno = -error;
4449edf8e2afSMika Westerberg                 goto out;
4450edf8e2afSMika Westerberg             }
4451edf8e2afSMika Westerberg             if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
4452edf8e2afSMika Westerberg                 goto out;
4453edf8e2afSMika Westerberg         }
4454edf8e2afSMika Westerberg     }
4455edf8e2afSMika Westerberg 
4456edf8e2afSMika Westerberg  out:
4457edf8e2afSMika Westerberg     free_note_info(&info);
4458edf8e2afSMika Westerberg     if (mm != NULL)
4459edf8e2afSMika Westerberg         vma_delete(mm);
4460edf8e2afSMika Westerberg     (void) close(fd);
4461edf8e2afSMika Westerberg 
4462edf8e2afSMika Westerberg     if (errno != 0)
4463edf8e2afSMika Westerberg         return (-errno);
4464edf8e2afSMika Westerberg     return (0);
4465edf8e2afSMika Westerberg }
4466edf8e2afSMika Westerberg #endif /* USE_ELF_CORE_DUMP */
4467edf8e2afSMika Westerberg 
4468e5fe0c52Spbrook void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
4469e5fe0c52Spbrook {
4470e5fe0c52Spbrook     init_thread(regs, infop);
4471e5fe0c52Spbrook }
4472