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