xref: /linux/arch/arm64/kvm/hyp/nvhe/gen-hyprel.c (revision 303bff3637d13f0ecbb280c7cb403470c440a2a6)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2020 - Google LLC
4  * Author: David Brazdil <dbrazdil@google.com>
5  *
6  * Generates relocation information used by the kernel to convert
7  * absolute addresses in hyp data from kernel VAs to hyp VAs.
8  *
9  * This is necessary because hyp code is linked into the same binary
10  * as the kernel but executes under different memory mappings.
11  * If the compiler used absolute addressing, those addresses need to
12  * be converted before they are used by hyp code.
13  *
14  * The input of this program is the relocatable ELF object containing
15  * all hyp code/data, not yet linked into vmlinux. Hyp section names
16  * should have been prefixed with `.hyp` at this point.
17  *
18  * The output (printed to stdout) is an assembly file containing
19  * an array of 32-bit integers and static relocations that instruct
20  * the linker of `vmlinux` to populate the array entries with offsets
21  * to positions in the kernel binary containing VAs used by hyp code.
22  *
23  * Note that dynamic relocations could be used for the same purpose.
24  * However, those are only generated if CONFIG_RELOCATABLE=y.
25  */
26 
27 #include <elf.h>
28 #include <endian.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/mman.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39 
40 #include <generated/autoconf.h>
41 
42 #define HYP_SECTION_PREFIX		".hyp"
43 #define HYP_RELOC_SECTION		".hyp.reloc"
44 #define HYP_SECTION_SYMBOL_PREFIX	"__hyp_section_"
45 
46 /*
47  * AArch64 relocation type constants.
48  * Included in case these are not defined in the host toolchain.
49  */
50 #ifndef R_AARCH64_ABS64
51 #define R_AARCH64_ABS64			257
52 #endif
53 #ifndef R_AARCH64_ABS32
54 #define R_AARCH64_ABS32			258
55 #endif
56 #ifndef R_AARCH64_PREL64
57 #define R_AARCH64_PREL64		260
58 #endif
59 #ifndef R_AARCH64_PREL32
60 #define R_AARCH64_PREL32		261
61 #endif
62 #ifndef R_AARCH64_PREL16
63 #define R_AARCH64_PREL16		262
64 #endif
65 #ifndef R_AARCH64_PLT32
66 #define R_AARCH64_PLT32			314
67 #endif
68 #ifndef R_AARCH64_LD_PREL_LO19
69 #define R_AARCH64_LD_PREL_LO19		273
70 #endif
71 #ifndef R_AARCH64_ADR_PREL_LO21
72 #define R_AARCH64_ADR_PREL_LO21		274
73 #endif
74 #ifndef R_AARCH64_ADR_PREL_PG_HI21
75 #define R_AARCH64_ADR_PREL_PG_HI21	275
76 #endif
77 #ifndef R_AARCH64_ADR_PREL_PG_HI21_NC
78 #define R_AARCH64_ADR_PREL_PG_HI21_NC	276
79 #endif
80 #ifndef R_AARCH64_ADD_ABS_LO12_NC
81 #define R_AARCH64_ADD_ABS_LO12_NC	277
82 #endif
83 #ifndef R_AARCH64_LDST8_ABS_LO12_NC
84 #define R_AARCH64_LDST8_ABS_LO12_NC	278
85 #endif
86 #ifndef R_AARCH64_TSTBR14
87 #define R_AARCH64_TSTBR14		279
88 #endif
89 #ifndef R_AARCH64_CONDBR19
90 #define R_AARCH64_CONDBR19		280
91 #endif
92 #ifndef R_AARCH64_JUMP26
93 #define R_AARCH64_JUMP26		282
94 #endif
95 #ifndef R_AARCH64_CALL26
96 #define R_AARCH64_CALL26		283
97 #endif
98 #ifndef R_AARCH64_LDST16_ABS_LO12_NC
99 #define R_AARCH64_LDST16_ABS_LO12_NC	284
100 #endif
101 #ifndef R_AARCH64_LDST32_ABS_LO12_NC
102 #define R_AARCH64_LDST32_ABS_LO12_NC	285
103 #endif
104 #ifndef R_AARCH64_LDST64_ABS_LO12_NC
105 #define R_AARCH64_LDST64_ABS_LO12_NC	286
106 #endif
107 #ifndef R_AARCH64_MOVW_PREL_G0
108 #define R_AARCH64_MOVW_PREL_G0		287
109 #endif
110 #ifndef R_AARCH64_MOVW_PREL_G0_NC
111 #define R_AARCH64_MOVW_PREL_G0_NC	288
112 #endif
113 #ifndef R_AARCH64_MOVW_PREL_G1
114 #define R_AARCH64_MOVW_PREL_G1		289
115 #endif
116 #ifndef R_AARCH64_MOVW_PREL_G1_NC
117 #define R_AARCH64_MOVW_PREL_G1_NC	290
118 #endif
119 #ifndef R_AARCH64_MOVW_PREL_G2
120 #define R_AARCH64_MOVW_PREL_G2		291
121 #endif
122 #ifndef R_AARCH64_MOVW_PREL_G2_NC
123 #define R_AARCH64_MOVW_PREL_G2_NC	292
124 #endif
125 #ifndef R_AARCH64_MOVW_PREL_G3
126 #define R_AARCH64_MOVW_PREL_G3		293
127 #endif
128 #ifndef R_AARCH64_LDST128_ABS_LO12_NC
129 #define R_AARCH64_LDST128_ABS_LO12_NC	299
130 #endif
131 
132 /* Global state of the processed ELF. */
133 static struct {
134 	const char	*path;
135 	char		*begin;
136 	size_t		size;
137 	Elf64_Ehdr	*ehdr;
138 	Elf64_Shdr	*sh_table;
139 	const char	*sh_string;
140 } elf;
141 
142 #define elf16toh(x)	le16toh(x)
143 #define elf32toh(x)	le32toh(x)
144 #define elf64toh(x)	le64toh(x)
145 
146 #define ELFENDIAN	ELFDATA2LSB
147 
148 #define fatal_error(fmt, ...)						\
149 	({								\
150 		fprintf(stderr, "error: %s: " fmt "\n",			\
151 			elf.path, ## __VA_ARGS__);			\
152 		exit(EXIT_FAILURE);					\
153 		__builtin_unreachable();				\
154 	})
155 
156 #define fatal_perror(msg)						\
157 	({								\
158 		fprintf(stderr, "error: %s: " msg ": %s\n",		\
159 			elf.path, strerror(errno));			\
160 		exit(EXIT_FAILURE);					\
161 		__builtin_unreachable();				\
162 	})
163 
164 #define assert_op(lhs, rhs, fmt, op)					\
165 	({								\
166 		typeof(lhs) _lhs = (lhs);				\
167 		typeof(rhs) _rhs = (rhs);				\
168 									\
169 		if (!(_lhs op _rhs)) {					\
170 			fatal_error("assertion " #lhs " " #op " " #rhs	\
171 				" failed (lhs=" fmt ", rhs=" fmt	\
172 				", line=%d)", _lhs, _rhs, __LINE__);	\
173 		}							\
174 	})
175 
176 #define assert_eq(lhs, rhs, fmt)	assert_op(lhs, rhs, fmt, ==)
177 #define assert_ne(lhs, rhs, fmt)	assert_op(lhs, rhs, fmt, !=)
178 #define assert_lt(lhs, rhs, fmt)	assert_op(lhs, rhs, fmt, <)
179 #define assert_ge(lhs, rhs, fmt)	assert_op(lhs, rhs, fmt, >=)
180 
181 /*
182  * Return a pointer of a given type at a given offset from
183  * the beginning of the ELF file.
184  */
185 #define elf_ptr(type, off) ((type *)(elf.begin + (off)))
186 
187 /* Iterate over all sections in the ELF. */
188 #define for_each_section(var) \
189 	for (var = elf.sh_table; var < elf.sh_table + elf16toh(elf.ehdr->e_shnum); ++var)
190 
191 /* Iterate over all Elf64_Rela relocations in a given section. */
192 #define for_each_rela(shdr, var)					\
193 	for (var = elf_ptr(Elf64_Rela, elf64toh(shdr->sh_offset));	\
194 	     var < elf_ptr(Elf64_Rela, elf64toh(shdr->sh_offset) + elf64toh(shdr->sh_size)); var++)
195 
196 /* True if a string starts with a given prefix. */
starts_with(const char * str,const char * prefix)197 static inline bool starts_with(const char *str, const char *prefix)
198 {
199 	return memcmp(str, prefix, strlen(prefix)) == 0;
200 }
201 
202 /* Returns a string containing the name of a given section. */
section_name(Elf64_Shdr * shdr)203 static inline const char *section_name(Elf64_Shdr *shdr)
204 {
205 	return elf.sh_string + elf32toh(shdr->sh_name);
206 }
207 
208 /* Returns a pointer to the first byte of section data. */
section_begin(Elf64_Shdr * shdr)209 static inline const char *section_begin(Elf64_Shdr *shdr)
210 {
211 	return elf_ptr(char, elf64toh(shdr->sh_offset));
212 }
213 
214 /* Find a section by its offset from the beginning of the file. */
section_by_off(Elf64_Off off)215 static inline Elf64_Shdr *section_by_off(Elf64_Off off)
216 {
217 	assert_ne(off, 0UL, "%lu");
218 	return elf_ptr(Elf64_Shdr, off);
219 }
220 
221 /* Find a section by its index. */
section_by_idx(uint16_t idx)222 static inline Elf64_Shdr *section_by_idx(uint16_t idx)
223 {
224 	assert_ne(idx, SHN_UNDEF, "%u");
225 	return &elf.sh_table[idx];
226 }
227 
228 /*
229  * Memory-map the given ELF file, perform sanity checks, and
230  * populate global state.
231  */
init_elf(const char * path)232 static void init_elf(const char *path)
233 {
234 	int fd, ret;
235 	struct stat stat;
236 
237 	/* Store path in the global struct for error printing. */
238 	elf.path = path;
239 
240 	/* Open the ELF file. */
241 	fd = open(path, O_RDONLY);
242 	if (fd < 0)
243 		fatal_perror("Could not open ELF file");
244 
245 	/* Get status of ELF file to obtain its size. */
246 	ret = fstat(fd, &stat);
247 	if (ret < 0) {
248 		close(fd);
249 		fatal_perror("Could not get status of ELF file");
250 	}
251 
252 	/* mmap() the entire ELF file read-only at an arbitrary address. */
253 	elf.begin = mmap(0, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
254 	if (elf.begin == MAP_FAILED) {
255 		close(fd);
256 		fatal_perror("Could not mmap ELF file");
257 	}
258 
259 	/* mmap() was successful, close the FD. */
260 	close(fd);
261 
262 	/* Get pointer to the ELF header. */
263 	assert_ge(stat.st_size, sizeof(*elf.ehdr), "%lu");
264 	elf.ehdr = elf_ptr(Elf64_Ehdr, 0);
265 
266 	/* Check the ELF magic. */
267 	assert_eq(elf.ehdr->e_ident[EI_MAG0], ELFMAG0, "0x%x");
268 	assert_eq(elf.ehdr->e_ident[EI_MAG1], ELFMAG1, "0x%x");
269 	assert_eq(elf.ehdr->e_ident[EI_MAG2], ELFMAG2, "0x%x");
270 	assert_eq(elf.ehdr->e_ident[EI_MAG3], ELFMAG3, "0x%x");
271 
272 	/* Sanity check that this is an ELF64 relocatable object for AArch64. */
273 	assert_eq(elf.ehdr->e_ident[EI_CLASS], ELFCLASS64, "%u");
274 	assert_eq(elf.ehdr->e_ident[EI_DATA], ELFENDIAN, "%u");
275 	assert_eq(elf16toh(elf.ehdr->e_type), ET_REL, "%u");
276 	assert_eq(elf16toh(elf.ehdr->e_machine), EM_AARCH64, "%u");
277 
278 	/* Populate fields of the global struct. */
279 	elf.sh_table = section_by_off(elf64toh(elf.ehdr->e_shoff));
280 	elf.sh_string = section_begin(section_by_idx(elf16toh(elf.ehdr->e_shstrndx)));
281 }
282 
283 /* Print the prologue of the output ASM file. */
emit_prologue(void)284 static void emit_prologue(void)
285 {
286 	printf(".data\n"
287 	       ".pushsection " HYP_RELOC_SECTION ", \"a\"\n");
288 }
289 
290 /* Print ASM statements needed as a prologue to a processed hyp section. */
emit_section_prologue(const char * sh_orig_name)291 static void emit_section_prologue(const char *sh_orig_name)
292 {
293 	/* Declare the hyp section symbol. */
294 	printf(".global %s%s\n", HYP_SECTION_SYMBOL_PREFIX, sh_orig_name);
295 }
296 
297 /*
298  * Print ASM statements to create a hyp relocation entry for a given
299  * R_AARCH64_ABS64 relocation.
300  *
301  * The linker of vmlinux will populate the position given by `rela` with
302  * an absolute 64-bit kernel VA. If the kernel is relocatable, it will
303  * also generate a dynamic relocation entry so that the kernel can shift
304  * the address at runtime for KASLR.
305  *
306  * Emit a 32-bit offset from the current address to the position given
307  * by `rela`. This way the kernel can iterate over all kernel VAs used
308  * by hyp at runtime and convert them to hyp VAs. However, that offset
309  * will not be known until linking of `vmlinux`, so emit a PREL32
310  * relocation referencing a symbol that the hyp linker script put at
311  * the beginning of the relocated section + the offset from `rela`.
312  */
emit_rela_abs64(Elf64_Rela * rela,const char * sh_orig_name)313 static void emit_rela_abs64(Elf64_Rela *rela, const char *sh_orig_name)
314 {
315 	/* Offset of this reloc from the beginning of HYP_RELOC_SECTION. */
316 	static size_t reloc_offset;
317 
318 	/* Create storage for the 32-bit offset. */
319 	printf(".word 0\n");
320 
321 	/*
322 	 * Create a PREL32 relocation which instructs the linker of `vmlinux`
323 	 * to insert offset to position <base> + <offset>, where <base> is
324 	 * a symbol at the beginning of the relocated section, and <offset>
325 	 * is `rela->r_offset`.
326 	 */
327 	printf(".reloc %lu, R_AARCH64_PREL32, %s%s + 0x%lx\n",
328 	       reloc_offset, HYP_SECTION_SYMBOL_PREFIX, sh_orig_name,
329 	       elf64toh(rela->r_offset));
330 
331 	reloc_offset += 4;
332 }
333 
334 /* Print the epilogue of the output ASM file. */
emit_epilogue(void)335 static void emit_epilogue(void)
336 {
337 	printf(".popsection\n");
338 }
339 
340 /*
341  * Iterate over all RELA relocations in a given section and emit
342  * hyp relocation data for all absolute addresses in hyp code/data.
343  *
344  * Static relocations that generate PC-relative-addressing are ignored.
345  * Failure is reported for unexpected relocation types.
346  */
emit_rela_section(Elf64_Shdr * sh_rela)347 static void emit_rela_section(Elf64_Shdr *sh_rela)
348 {
349 	Elf64_Shdr *sh_orig = &elf.sh_table[elf32toh(sh_rela->sh_info)];
350 	const char *sh_orig_name = section_name(sh_orig);
351 	Elf64_Rela *rela;
352 
353 	/* Skip all non-hyp sections. */
354 	if (!starts_with(sh_orig_name, HYP_SECTION_PREFIX))
355 		return;
356 
357 	emit_section_prologue(sh_orig_name);
358 
359 	for_each_rela(sh_rela, rela) {
360 		uint32_t type = (uint32_t)elf64toh(rela->r_info);
361 
362 		/* Check that rela points inside the relocated section. */
363 		assert_lt(elf64toh(rela->r_offset), elf64toh(sh_orig->sh_size), "0x%lx");
364 
365 		switch (type) {
366 		/*
367 		 * Data relocations to generate absolute addressing.
368 		 * Emit a hyp relocation.
369 		 */
370 		case R_AARCH64_ABS64:
371 			emit_rela_abs64(rela, sh_orig_name);
372 			break;
373 		/* Allow 32-bit absolute relocation, for kCFI type hashes. */
374 		case R_AARCH64_ABS32:
375 			break;
376 		/* Allow position-relative data relocations. */
377 		case R_AARCH64_PREL64:
378 		case R_AARCH64_PREL32:
379 		case R_AARCH64_PREL16:
380 		case R_AARCH64_PLT32:
381 			break;
382 		/* Allow relocations to generate PC-relative addressing. */
383 		case R_AARCH64_LD_PREL_LO19:
384 		case R_AARCH64_ADR_PREL_LO21:
385 		case R_AARCH64_ADR_PREL_PG_HI21:
386 		case R_AARCH64_ADR_PREL_PG_HI21_NC:
387 		case R_AARCH64_ADD_ABS_LO12_NC:
388 		case R_AARCH64_LDST8_ABS_LO12_NC:
389 		case R_AARCH64_LDST16_ABS_LO12_NC:
390 		case R_AARCH64_LDST32_ABS_LO12_NC:
391 		case R_AARCH64_LDST64_ABS_LO12_NC:
392 		case R_AARCH64_LDST128_ABS_LO12_NC:
393 			break;
394 		/* Allow relative relocations for control-flow instructions. */
395 		case R_AARCH64_TSTBR14:
396 		case R_AARCH64_CONDBR19:
397 		case R_AARCH64_JUMP26:
398 		case R_AARCH64_CALL26:
399 			break;
400 		/* Allow group relocations to create PC-relative offset inline. */
401 		case R_AARCH64_MOVW_PREL_G0:
402 		case R_AARCH64_MOVW_PREL_G0_NC:
403 		case R_AARCH64_MOVW_PREL_G1:
404 		case R_AARCH64_MOVW_PREL_G1_NC:
405 		case R_AARCH64_MOVW_PREL_G2:
406 		case R_AARCH64_MOVW_PREL_G2_NC:
407 		case R_AARCH64_MOVW_PREL_G3:
408 			break;
409 		default:
410 			fatal_error("Unexpected RELA type %u", type);
411 		}
412 	}
413 }
414 
415 /* Iterate over all sections and emit hyp relocation data for RELA sections. */
emit_all_relocs(void)416 static void emit_all_relocs(void)
417 {
418 	Elf64_Shdr *shdr;
419 
420 	for_each_section(shdr) {
421 		switch (elf32toh(shdr->sh_type)) {
422 		case SHT_REL:
423 			fatal_error("Unexpected SHT_REL section \"%s\"",
424 				section_name(shdr));
425 		case SHT_RELA:
426 			emit_rela_section(shdr);
427 			break;
428 		}
429 	}
430 }
431 
main(int argc,const char ** argv)432 int main(int argc, const char **argv)
433 {
434 	if (argc != 2) {
435 		fprintf(stderr, "Usage: %s <elf_input>\n", argv[0]);
436 		return EXIT_FAILURE;
437 	}
438 
439 	init_elf(argv[1]);
440 
441 	emit_prologue();
442 	emit_all_relocs();
443 	emit_epilogue();
444 
445 	return EXIT_SUCCESS;
446 }
447