summaryrefslogtreecommitdiff
path: root/arch/loongarch/include/asm/elf.h
blob: f3960b18a90e9baf41f45a5570050885a0b7b240 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
 */
#ifndef _ASM_ELF_H
#define _ASM_ELF_H

#include <linux/auxvec.h>
#include <linux/fs.h>
#include <uapi/linux/elf.h>

#include <asm/current.h>
#include <asm/vdso.h>

/* The ABI of a file. */
#define EF_LOONGARCH_ABI_LP64_SOFT_FLOAT	0x1
#define EF_LOONGARCH_ABI_LP64_SINGLE_FLOAT	0x2
#define EF_LOONGARCH_ABI_LP64_DOUBLE_FLOAT	0x3

#define EF_LOONGARCH_ABI_ILP32_SOFT_FLOAT	0x5
#define EF_LOONGARCH_ABI_ILP32_SINGLE_FLOAT	0x6
#define EF_LOONGARCH_ABI_ILP32_DOUBLE_FLOAT	0x7

/* LoongArch relocation types used by the dynamic linker */
#define R_LARCH_NONE				0
#define R_LARCH_32				1
#define R_LARCH_64				2
#define R_LARCH_RELATIVE			3
#define R_LARCH_COPY				4
#define R_LARCH_JUMP_SLOT			5
#define R_LARCH_TLS_DTPMOD32			6
#define R_LARCH_TLS_DTPMOD64			7
#define R_LARCH_TLS_DTPREL32			8
#define R_LARCH_TLS_DTPREL64			9
#define R_LARCH_TLS_TPREL32			10
#define R_LARCH_TLS_TPREL64			11
#define R_LARCH_IRELATIVE			12
#define R_LARCH_MARK_LA				20
#define R_LARCH_MARK_PCREL			21
#define R_LARCH_SOP_PUSH_PCREL			22
#define R_LARCH_SOP_PUSH_ABSOLUTE		23
#define R_LARCH_SOP_PUSH_DUP			24
#define R_LARCH_SOP_PUSH_GPREL			25
#define R_LARCH_SOP_PUSH_TLS_TPREL		26
#define R_LARCH_SOP_PUSH_TLS_GOT		27
#define R_LARCH_SOP_PUSH_TLS_GD			28
#define R_LARCH_SOP_PUSH_PLT_PCREL		29
#define R_LARCH_SOP_ASSERT			30
#define R_LARCH_SOP_NOT				31
#define R_LARCH_SOP_SUB				32
#define R_LARCH_SOP_SL				33
#define R_LARCH_SOP_SR				34
#define R_LARCH_SOP_ADD				35
#define R_LARCH_SOP_AND				36
#define R_LARCH_SOP_IF_ELSE			37
#define R_LARCH_SOP_POP_32_S_10_5		38
#define R_LARCH_SOP_POP_32_U_10_12		39
#define R_LARCH_SOP_POP_32_S_10_12		40
#define R_LARCH_SOP_POP_32_S_10_16		41
#define R_LARCH_SOP_POP_32_S_10_16_S2		42
#define R_LARCH_SOP_POP_32_S_5_20		43
#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2	44
#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2	45
#define R_LARCH_SOP_POP_32_U			46
#define R_LARCH_ADD8				47
#define R_LARCH_ADD16				48
#define R_LARCH_ADD24				49
#define R_LARCH_ADD32				50
#define R_LARCH_ADD64				51
#define R_LARCH_SUB8				52
#define R_LARCH_SUB16				53
#define R_LARCH_SUB24				54
#define R_LARCH_SUB32				55
#define R_LARCH_SUB64				56
#define R_LARCH_GNU_VTINHERIT			57
#define R_LARCH_GNU_VTENTRY			58

#ifndef ELF_ARCH

/* ELF register definitions */

/*
 * General purpose have the following registers:
 *	Register	Number
 *	GPRs		32
 *	ORIG_A0		1
 *	ERA		1
 *	BADVADDR	1
 *	CRMD		1
 *	PRMD		1
 *	EUEN		1
 *	ECFG		1
 *	ESTAT		1
 *	Reserved	5
 */
#define ELF_NGREG	45

/*
 * Floating point have the following registers:
 *	Register	Number
 *	FPR		32
 *	FCC		1
 *	FCSR		1
 */
#define ELF_NFPREG	34

typedef unsigned long elf_greg_t;
typedef elf_greg_t elf_gregset_t[ELF_NGREG];

typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];

void loongarch_dump_regs64(u64 *uregs, const struct pt_regs *regs);

#ifdef CONFIG_32BIT
/*
 * This is used to ensure we don't load something for the wrong architecture.
 */
#define elf_check_arch elf32_check_arch

/*
 * These are used to set parameters in the core dumps.
 */
#define ELF_CLASS	ELFCLASS32

#define ELF_CORE_COPY_REGS(dest, regs) \
	loongarch_dump_regs32((u32 *)&(dest), (regs));

#endif /* CONFIG_32BIT */

#ifdef CONFIG_64BIT
/*
 * This is used to ensure we don't load something for the wrong architecture.
 */
#define elf_check_arch elf64_check_arch

/*
 * These are used to set parameters in the core dumps.
 */
#define ELF_CLASS	ELFCLASS64

#define ELF_CORE_COPY_REGS(dest, regs) \
	loongarch_dump_regs64((u64 *)&(dest), (regs));

#endif /* CONFIG_64BIT */

/*
 * These are used to set parameters in the core dumps.
 */
#define ELF_DATA	ELFDATA2LSB
#define ELF_ARCH	EM_LOONGARCH

#endif /* !defined(ELF_ARCH) */

#define loongarch_elf_check_machine(x) ((x)->e_machine == EM_LOONGARCH)

#define vmcore_elf32_check_arch loongarch_elf_check_machine
#define vmcore_elf64_check_arch loongarch_elf_check_machine

/*
 * Return non-zero if HDR identifies an 32bit ELF binary.
 */
#define elf32_check_arch(hdr)						\
({									\
	int __res = 1;							\
	struct elfhdr *__h = (hdr);					\
									\
	if (!loongarch_elf_check_machine(__h))				\
		__res = 0;						\
	if (__h->e_ident[EI_CLASS] != ELFCLASS32)			\
		__res = 0;						\
									\
	__res;								\
})

/*
 * Return non-zero if HDR identifies an 64bit ELF binary.
 */
#define elf64_check_arch(hdr)						\
({									\
	int __res = 1;							\
	struct elfhdr *__h = (hdr);					\
									\
	if (!loongarch_elf_check_machine(__h))				\
		__res = 0;						\
	if (__h->e_ident[EI_CLASS] != ELFCLASS64)			\
		__res = 0;						\
									\
	__res;								\
})

#ifdef CONFIG_32BIT

#define SET_PERSONALITY2(ex, state)					\
do {									\
	current->thread.vdso = &vdso_info;				\
									\
	loongarch_set_personality_fcsr(state);				\
									\
	if (personality(current->personality) != PER_LINUX)		\
		set_personality(PER_LINUX);				\
} while (0)

#endif /* CONFIG_32BIT */

#ifdef CONFIG_64BIT

#define SET_PERSONALITY2(ex, state)					\
do {									\
	unsigned int p;							\
									\
	clear_thread_flag(TIF_32BIT_REGS);				\
	clear_thread_flag(TIF_32BIT_ADDR);				\
									\
	current->thread.vdso = &vdso_info;				\
	loongarch_set_personality_fcsr(state);				\
									\
	p = personality(current->personality);				\
	if (p != PER_LINUX32 && p != PER_LINUX)				\
		set_personality(PER_LINUX);				\
} while (0)

#endif /* CONFIG_64BIT */

#define CORE_DUMP_USE_REGSET
#define ELF_EXEC_PAGESIZE	PAGE_SIZE

/*
 * This yields a mask that user programs can use to figure out what
 * instruction set this cpu supports. This could be done in userspace,
 * but it's not easy, and we've already done it here.
 */

#define ELF_HWCAP	(elf_hwcap)
extern unsigned int elf_hwcap;
#include <asm/hwcap.h>

/*
 * This yields a string that ld.so will use to load implementation
 * specific libraries for optimization.	 This is more specific in
 * intent than poking at uname or /proc/cpuinfo.
 */

#define ELF_PLATFORM  __elf_platform
extern const char *__elf_platform;

#define ELF_PLAT_INIT(_r, load_addr)	do { \
	_r->regs[1] = _r->regs[2] = _r->regs[3] = _r->regs[4] = 0;	\
	_r->regs[5] = _r->regs[6] = _r->regs[7] = _r->regs[8] = 0;	\
	_r->regs[9] = _r->regs[10] = _r->regs[11] = _r->regs[12] = 0;	\
	_r->regs[13] = _r->regs[14] = _r->regs[15] = _r->regs[16] = 0;	\
	_r->regs[17] = _r->regs[18] = _r->regs[19] = _r->regs[20] = 0;	\
	_r->regs[21] = _r->regs[22] = _r->regs[23] = _r->regs[24] = 0;	\
	_r->regs[25] = _r->regs[26] = _r->regs[27] = _r->regs[28] = 0;	\
	_r->regs[29] = _r->regs[30] = _r->regs[31] = 0;			\
} while (0)

/*
 * This is the location that an ET_DYN program is loaded if exec'ed. Typical
 * use of this is to invoke "./ld.so someprog" to test out a new version of
 * the loader. We need to make sure that it is out of the way of the program
 * that it will "exec", and that there is sufficient room for the brk.
 */

#define ELF_ET_DYN_BASE		(TASK_SIZE / 3 * 2)

/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
#define ARCH_DLINFO							\
do {									\
	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
		    (unsigned long)current->mm->context.vdso);		\
} while (0)

#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
struct linux_binprm;
extern int arch_setup_additional_pages(struct linux_binprm *bprm,
				       int uses_interp);

struct arch_elf_state {
	int fp_abi;
	int interp_fp_abi;
};

#define LOONGARCH_ABI_FP_ANY	(0)

#define INIT_ARCH_ELF_STATE {			\
	.fp_abi = LOONGARCH_ABI_FP_ANY,		\
	.interp_fp_abi = LOONGARCH_ABI_FP_ANY,	\
}

#define elf_read_implies_exec(ex, exec_stk) (exec_stk == EXSTACK_DEFAULT)

extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf,
			    bool is_interp, struct arch_elf_state *state);

extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr,
			  struct arch_elf_state *state);

extern void loongarch_set_personality_fcsr(struct arch_elf_state *state);

#endif /* _ASM_ELF_H */