GNU Linux-libre 4.19.286-gnu1
[releases.git] / arch / x86 / boot / compressed / misc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * misc.c
4  *
5  * This is a collection of several routines used to extract the kernel
6  * which includes KASLR relocation, decompression, ELF parsing, and
7  * relocation processing. Additionally included are the screen and serial
8  * output functions and related debugging support functions.
9  *
10  * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
11  * puts by Nick Holloway 1993, better puts by Martin Mares 1995
12  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
13  */
14
15 #include "misc.h"
16 #include "error.h"
17 #include "pgtable.h"
18 #include "../string.h"
19 #include "../voffset.h"
20 #include <asm/bootparam_utils.h>
21
22 /*
23  * WARNING!!
24  * This code is compiled with -fPIC and it is relocated dynamically at
25  * run time, but no relocation processing is performed. This means that
26  * it is not safe to place pointers in static structures.
27  */
28
29 /* Macros used by the included decompressor code below. */
30 #define STATIC          static
31
32 /*
33  * Use normal definitions of mem*() from string.c. There are already
34  * included header files which expect a definition of memset() and by
35  * the time we define memset macro, it is too late.
36  */
37 #undef memcpy
38 #undef memset
39 #define memzero(s, n)   memset((s), 0, (n))
40 #define memmove         memmove
41
42 /* Functions used by the included decompressor code below. */
43 void *memmove(void *dest, const void *src, size_t n);
44
45 /*
46  * This is set up by the setup-routine at boot-time
47  */
48 struct boot_params *boot_params;
49
50 memptr free_mem_ptr;
51 memptr free_mem_end_ptr;
52
53 static char *vidmem;
54 static int vidport;
55 static int lines, cols;
56
57 #ifdef CONFIG_KERNEL_GZIP
58 #include "../../../../lib/decompress_inflate.c"
59 #endif
60
61 #ifdef CONFIG_KERNEL_BZIP2
62 #include "../../../../lib/decompress_bunzip2.c"
63 #endif
64
65 #ifdef CONFIG_KERNEL_LZMA
66 #include "../../../../lib/decompress_unlzma.c"
67 #endif
68
69 #ifdef CONFIG_KERNEL_XZ
70 #include "../../../../lib/decompress_unxz.c"
71 #endif
72
73 #ifdef CONFIG_KERNEL_LZO
74 #include "../../../../lib/decompress_unlzo.c"
75 #endif
76
77 #ifdef CONFIG_KERNEL_LZ4
78 #include "../../../../lib/decompress_unlz4.c"
79 #endif
80 /*
81  * NOTE: When adding a new decompressor, please update the analysis in
82  * ../header.S.
83  */
84
85 static void scroll(void)
86 {
87         int i;
88
89         memmove(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);
90         for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2)
91                 vidmem[i] = ' ';
92 }
93
94 #define XMTRDY          0x20
95
96 #define TXR             0       /*  Transmit register (WRITE) */
97 #define LSR             5       /*  Line Status               */
98 static void serial_putchar(int ch)
99 {
100         unsigned timeout = 0xffff;
101
102         while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
103                 cpu_relax();
104
105         outb(ch, early_serial_base + TXR);
106 }
107
108 void __putstr(const char *s)
109 {
110         int x, y, pos;
111         char c;
112
113         if (early_serial_base) {
114                 const char *str = s;
115                 while (*str) {
116                         if (*str == '\n')
117                                 serial_putchar('\r');
118                         serial_putchar(*str++);
119                 }
120         }
121
122         if (lines == 0 || cols == 0)
123                 return;
124
125         x = boot_params->screen_info.orig_x;
126         y = boot_params->screen_info.orig_y;
127
128         while ((c = *s++) != '\0') {
129                 if (c == '\n') {
130                         x = 0;
131                         if (++y >= lines) {
132                                 scroll();
133                                 y--;
134                         }
135                 } else {
136                         vidmem[(x + cols * y) * 2] = c;
137                         if (++x >= cols) {
138                                 x = 0;
139                                 if (++y >= lines) {
140                                         scroll();
141                                         y--;
142                                 }
143                         }
144                 }
145         }
146
147         boot_params->screen_info.orig_x = x;
148         boot_params->screen_info.orig_y = y;
149
150         pos = (x + cols * y) * 2;       /* Update cursor position */
151         outb(14, vidport);
152         outb(0xff & (pos >> 9), vidport+1);
153         outb(15, vidport);
154         outb(0xff & (pos >> 1), vidport+1);
155 }
156
157 void __puthex(unsigned long value)
158 {
159         char alpha[2] = "0";
160         int bits;
161
162         for (bits = sizeof(value) * 8 - 4; bits >= 0; bits -= 4) {
163                 unsigned long digit = (value >> bits) & 0xf;
164
165                 if (digit < 0xA)
166                         alpha[0] = '0' + digit;
167                 else
168                         alpha[0] = 'a' + (digit - 0xA);
169
170                 __putstr(alpha);
171         }
172 }
173
174 #if CONFIG_X86_NEED_RELOCS
175 static void handle_relocations(void *output, unsigned long output_len,
176                                unsigned long virt_addr)
177 {
178         int *reloc;
179         unsigned long delta, map, ptr;
180         unsigned long min_addr = (unsigned long)output;
181         unsigned long max_addr = min_addr + (VO___bss_start - VO__text);
182
183         /*
184          * Calculate the delta between where vmlinux was linked to load
185          * and where it was actually loaded.
186          */
187         delta = min_addr - LOAD_PHYSICAL_ADDR;
188
189         /*
190          * The kernel contains a table of relocation addresses. Those
191          * addresses have the final load address of the kernel in virtual
192          * memory. We are currently working in the self map. So we need to
193          * create an adjustment for kernel memory addresses to the self map.
194          * This will involve subtracting out the base address of the kernel.
195          */
196         map = delta - __START_KERNEL_map;
197
198         /*
199          * 32-bit always performs relocations. 64-bit relocations are only
200          * needed if KASLR has chosen a different starting address offset
201          * from __START_KERNEL_map.
202          */
203         if (IS_ENABLED(CONFIG_X86_64))
204                 delta = virt_addr - LOAD_PHYSICAL_ADDR;
205
206         if (!delta) {
207                 debug_putstr("No relocation needed... ");
208                 return;
209         }
210         debug_putstr("Performing relocations... ");
211
212         /*
213          * Process relocations: 32 bit relocations first then 64 bit after.
214          * Three sets of binary relocations are added to the end of the kernel
215          * before compression. Each relocation table entry is the kernel
216          * address of the location which needs to be updated stored as a
217          * 32-bit value which is sign extended to 64 bits.
218          *
219          * Format is:
220          *
221          * kernel bits...
222          * 0 - zero terminator for 64 bit relocations
223          * 64 bit relocation repeated
224          * 0 - zero terminator for inverse 32 bit relocations
225          * 32 bit inverse relocation repeated
226          * 0 - zero terminator for 32 bit relocations
227          * 32 bit relocation repeated
228          *
229          * So we work backwards from the end of the decompressed image.
230          */
231         for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) {
232                 long extended = *reloc;
233                 extended += map;
234
235                 ptr = (unsigned long)extended;
236                 if (ptr < min_addr || ptr > max_addr)
237                         error("32-bit relocation outside of kernel!\n");
238
239                 *(uint32_t *)ptr += delta;
240         }
241 #ifdef CONFIG_X86_64
242         while (*--reloc) {
243                 long extended = *reloc;
244                 extended += map;
245
246                 ptr = (unsigned long)extended;
247                 if (ptr < min_addr || ptr > max_addr)
248                         error("inverse 32-bit relocation outside of kernel!\n");
249
250                 *(int32_t *)ptr -= delta;
251         }
252         for (reloc--; *reloc; reloc--) {
253                 long extended = *reloc;
254                 extended += map;
255
256                 ptr = (unsigned long)extended;
257                 if (ptr < min_addr || ptr > max_addr)
258                         error("64-bit relocation outside of kernel!\n");
259
260                 *(uint64_t *)ptr += delta;
261         }
262 #endif
263 }
264 #else
265 static inline void handle_relocations(void *output, unsigned long output_len,
266                                       unsigned long virt_addr)
267 { }
268 #endif
269
270 static void parse_elf(void *output)
271 {
272 #ifdef CONFIG_X86_64
273         Elf64_Ehdr ehdr;
274         Elf64_Phdr *phdrs, *phdr;
275 #else
276         Elf32_Ehdr ehdr;
277         Elf32_Phdr *phdrs, *phdr;
278 #endif
279         void *dest;
280         int i;
281
282         memcpy(&ehdr, output, sizeof(ehdr));
283         if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
284            ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
285            ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
286            ehdr.e_ident[EI_MAG3] != ELFMAG3) {
287                 error("Kernel is not a valid ELF file");
288                 return;
289         }
290
291         debug_putstr("Parsing ELF... ");
292
293         phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
294         if (!phdrs)
295                 error("Failed to allocate space for phdrs");
296
297         memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);
298
299         for (i = 0; i < ehdr.e_phnum; i++) {
300                 phdr = &phdrs[i];
301
302                 switch (phdr->p_type) {
303                 case PT_LOAD:
304 #ifdef CONFIG_X86_64
305                         if ((phdr->p_align % 0x200000) != 0)
306                                 error("Alignment of LOAD segment isn't multiple of 2MB");
307 #endif
308 #ifdef CONFIG_RELOCATABLE
309                         dest = output;
310                         dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR);
311 #else
312                         dest = (void *)(phdr->p_paddr);
313 #endif
314                         memmove(dest, output + phdr->p_offset, phdr->p_filesz);
315                         break;
316                 default: /* Ignore other PT_* */ break;
317                 }
318         }
319
320         free(phdrs);
321 }
322
323 /*
324  * The compressed kernel image (ZO), has been moved so that its position
325  * is against the end of the buffer used to hold the uncompressed kernel
326  * image (VO) and the execution environment (.bss, .brk), which makes sure
327  * there is room to do the in-place decompression. (See header.S for the
328  * calculations.)
329  *
330  *                             |-----compressed kernel image------|
331  *                             V                                  V
332  * 0                       extract_offset                      +INIT_SIZE
333  * |-----------|---------------|-------------------------|--------|
334  *             |               |                         |        |
335  *           VO__text      startup_32 of ZO          VO__end    ZO__end
336  *             ^                                         ^
337  *             |-------uncompressed kernel image---------|
338  *
339  */
340 asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
341                                   unsigned char *input_data,
342                                   unsigned long input_len,
343                                   unsigned char *output,
344                                   unsigned long output_len)
345 {
346         const unsigned long kernel_total_size = VO__end - VO__text;
347         unsigned long virt_addr = LOAD_PHYSICAL_ADDR;
348
349         /* Retain x86 boot parameters pointer passed from startup_32/64. */
350         boot_params = rmode;
351
352         /* Clear flags intended for solely in-kernel use. */
353         boot_params->hdr.loadflags &= ~KASLR_FLAG;
354
355         sanitize_boot_params(boot_params);
356
357         if (boot_params->screen_info.orig_video_mode == 7) {
358                 vidmem = (char *) 0xb0000;
359                 vidport = 0x3b4;
360         } else {
361                 vidmem = (char *) 0xb8000;
362                 vidport = 0x3d4;
363         }
364
365         lines = boot_params->screen_info.orig_video_lines;
366         cols = boot_params->screen_info.orig_video_cols;
367
368         console_init();
369         debug_putstr("early console in extract_kernel\n");
370
371         free_mem_ptr     = heap;        /* Heap */
372         free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
373
374         /* Report initial kernel position details. */
375         debug_putaddr(input_data);
376         debug_putaddr(input_len);
377         debug_putaddr(output);
378         debug_putaddr(output_len);
379         debug_putaddr(kernel_total_size);
380
381 #ifdef CONFIG_X86_64
382         /* Report address of 32-bit trampoline */
383         debug_putaddr(trampoline_32bit);
384 #endif
385
386         /*
387          * The memory hole needed for the kernel is the larger of either
388          * the entire decompressed kernel plus relocation table, or the
389          * entire decompressed kernel plus .bss and .brk sections.
390          */
391         choose_random_location((unsigned long)input_data, input_len,
392                                 (unsigned long *)&output,
393                                 max(output_len, kernel_total_size),
394                                 &virt_addr);
395
396         /* Validate memory location choices. */
397         if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
398                 error("Destination physical address inappropriately aligned");
399         if (virt_addr & (MIN_KERNEL_ALIGN - 1))
400                 error("Destination virtual address inappropriately aligned");
401 #ifdef CONFIG_X86_64
402         if (heap > 0x3fffffffffffUL)
403                 error("Destination address too large");
404         if (virt_addr + max(output_len, kernel_total_size) > KERNEL_IMAGE_SIZE)
405                 error("Destination virtual address is beyond the kernel mapping area");
406 #else
407         if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff))
408                 error("Destination address too large");
409 #endif
410 #ifndef CONFIG_RELOCATABLE
411         if ((unsigned long)output != LOAD_PHYSICAL_ADDR)
412                 error("Destination address does not match LOAD_PHYSICAL_ADDR");
413         if (virt_addr != LOAD_PHYSICAL_ADDR)
414                 error("Destination virtual address changed when not relocatable");
415 #endif
416
417         debug_putstr("\nDecompressing Linux... ");
418         __decompress(input_data, input_len, NULL, NULL, output, output_len,
419                         NULL, error);
420         parse_elf(output);
421         handle_relocations(output, output_len, virt_addr);
422         debug_putstr("done.\nBooting the kernel.\n");
423         return output;
424 }
425
426 void fortify_panic(const char *name)
427 {
428         error("detected buffer overflow");
429 }