1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Decompression and self-relocation for the compressed kernel boot stub,
4 * based on arch/parisc/boot/compressed/misc.c.
5 *
6 * aboot loads the stub as an ordinary ELF at START_ADDR and jumps to it
7 * with the parameter page and stack already set up; vmlinux.lds.S
8 * explains why the stub has to be linked there. We decompress above our
9 * own bss and never write below START_ADDR, so what aboot prepared stays
10 * valid for the real kernel.
11 */
12
13 #include <linux/elf.h>
14 #include <linux/kernel.h>
15 #include <linux/string.h>
16 #include <linux/types.h>
17
18 #include <asm/hwrpb.h>
19 #include <asm/page.h>
20 #include <asm/pal.h>
21 #include <asm/setup.h>
22
23 #define STATIC static
24 #define memzero(s, n) memset((s), 0, (n))
25
26 /*
27 * decompress_unxz.c supplies its own memmove() unless the identifier is
28 * already a macro. We link our own build of arch/alpha/lib/memmove.S,
29 * which is better, so take that instead.
30 */
31 #define memmove memmove
32
33 extern char input_data[];
34 extern int input_len;
35 /* output_len is inserted by the linker, possibly at an unaligned address */
36 extern char output_len;
37
38 extern char _ebss[];
39 extern char trampoline_start[], trampoline_end[];
40
41 static unsigned long free_mem_ptr;
42 static unsigned long free_mem_end_ptr;
43 static unsigned long mem_end;
44
45 /* The stub has no console, so the message is only for debuggers. */
error(char * m)46 void __noreturn error(char *m)
47 {
48 while (1)
49 __halt();
50 }
51
52 #ifdef CONFIG_KERNEL_BZIP2
53 #include "../../../../lib/decompress_bunzip2.c"
54 #endif
55
56 #ifdef CONFIG_KERNEL_GZIP
57 #include "../../../../lib/decompress_inflate.c"
58 #endif
59
60 #ifdef CONFIG_KERNEL_LZ4
61 #include "../../../../lib/decompress_unlz4.c"
62 #endif
63
64 #ifdef CONFIG_KERNEL_LZMA
65 #include "../../../../lib/decompress_unlzma.c"
66 #endif
67
68 #ifdef CONFIG_KERNEL_LZO
69 #include "../../../../lib/decompress_unlzo.c"
70 #endif
71
72 #ifdef CONFIG_KERNEL_XZ
73 #include "../../../../lib/decompress_unxz.c"
74 #endif
75
76 #ifdef CONFIG_KERNEL_ZSTD
77 #include "../../../../lib/decompress_unzstd.c"
78 #endif
79
80 /* Scratch heap for the decompressors, larger than any of them needs. */
81 #define STUB_HEAP_SIZE (4 * 1024 * 1024)
82
83 /*
84 * Type punning through a packed struct, to avoid the warnings the regular
85 * get_unaligned_le32() produces when reading a char-typed symbol as an
86 * integer.
87 */
punned_get_unaligned_le32(const void * p)88 static u32 punned_get_unaligned_le32(const void *p)
89 {
90 const struct { __le32 x; } __packed *pp = p;
91
92 return le32_to_cpu(pp->x);
93 }
94
95 /*
96 * End of the usable memory cluster that holds the kernel, or 0 if the
97 * HWRPB does not describe one. Used to check that the decompressed image
98 * and the stub's scratch space fit before anything is written.
99 */
usable_memory_end(void)100 static unsigned long usable_memory_end(void)
101 {
102 struct hwrpb_struct *hwrpb;
103 struct memdesc_struct *memdesc;
104 unsigned long pfn = (START_ADDR - PAGE_OFFSET) >> PAGE_SHIFT;
105 unsigned long i;
106
107 hwrpb = (struct hwrpb_struct *)(PAGE_OFFSET + INIT_HWRPB->phys_addr);
108 memdesc = (struct memdesc_struct *)((unsigned long)hwrpb +
109 hwrpb->mddt_offset);
110
111 for (i = 0; i < memdesc->numclusters; i++) {
112 struct memclust_struct *cluster = &memdesc->cluster[i];
113 unsigned long end_pfn = cluster->start_pfn + cluster->numpages;
114
115 if (cluster->usage)
116 continue;
117 if (pfn >= cluster->start_pfn && pfn < end_pfn)
118 return PAGE_OFFSET + (end_pfn << PAGE_SHIFT);
119 }
120
121 return 0;
122 }
123
124 /*
125 * Move the decompressed kernel's single PT_LOAD segment down onto
126 * START_ADDR and jump to its entry point. The kernel is always linked
127 * with exactly one PT_LOAD whose p_vaddr equals its e_entry equals
128 * START_ADDR (see arch/alpha/kernel/vmlinux.lds.S); anything else we do
129 * not know how to boot.
130 *
131 * The copy cannot run from this stub, which is itself executing at
132 * START_ADDR; see trampoline.S.
133 */
relocate_and_jump(void * image)134 static void __noreturn relocate_and_jump(void *image)
135 {
136 void (*trampoline)(unsigned long dest, unsigned long src,
137 unsigned long filesz, unsigned long memsz,
138 unsigned long entry);
139 unsigned long tramp_len = trampoline_end - trampoline_start;
140 Elf64_Phdr phdr, load_phdr = {};
141 Elf64_Ehdr ehdr;
142 int i, found_load = 0;
143 unsigned long tramp;
144
145 memcpy(&ehdr, image, sizeof(ehdr));
146
147 if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
148 ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
149 ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
150 ehdr.e_ident[EI_MAG3] != ELFMAG3 ||
151 ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
152 ehdr.e_ident[EI_DATA] != ELFDATA2LSB ||
153 ehdr.e_machine != EM_ALPHA ||
154 ehdr.e_type != ET_EXEC ||
155 ehdr.e_entry != START_ADDR)
156 error("Not a bootable Alpha kernel image");
157
158 for (i = 0; i < ehdr.e_phnum; i++) {
159 memcpy(&phdr, image + ehdr.e_phoff + i * ehdr.e_phentsize,
160 sizeof(phdr));
161
162 if (phdr.p_type != PT_LOAD)
163 continue;
164 if (found_load || phdr.p_vaddr != START_ADDR)
165 error("Unexpected kernel segment layout");
166 found_load = 1;
167 load_phdr = phdr;
168 }
169 if (!found_load)
170 error("Kernel image has no PT_LOAD segment");
171
172 /*
173 * The trampoline has to outlive both the scratch heap it is copied
174 * into and the region it is about to write, which extends past the
175 * kernel's file image to the end of its bss.
176 */
177 tramp = ALIGN(max(free_mem_end_ptr, START_ADDR + load_phdr.p_memsz), 8);
178 if (mem_end && tramp + tramp_len > mem_end)
179 error("Not enough memory to relocate the kernel");
180
181 memcpy((void *)tramp, trampoline_start, tramp_len);
182 imb();
183
184 trampoline = (void *)tramp;
185 trampoline(load_phdr.p_vaddr,
186 (unsigned long)image + load_phdr.p_offset,
187 load_phdr.p_filesz, load_phdr.p_memsz, ehdr.e_entry);
188 unreachable();
189 }
190
decompress_and_boot(void)191 void __noreturn decompress_and_boot(void)
192 {
193 unsigned long image_len = punned_get_unaligned_le32(&output_len);
194 void *image = (void *)ALIGN((unsigned long)_ebss, PAGE_SIZE);
195
196 free_mem_ptr = ALIGN((unsigned long)image + image_len, PAGE_SIZE);
197 free_mem_end_ptr = free_mem_ptr + STUB_HEAP_SIZE;
198
199 mem_end = usable_memory_end();
200 if (mem_end && free_mem_end_ptr > mem_end)
201 error("Not enough memory to decompress the kernel");
202
203 /* Some decompressors report failure only through the return value. */
204 if (__decompress(input_data, input_len, NULL, NULL, image, image_len,
205 NULL, error))
206 error("Kernel decompression failed");
207
208 relocate_and_jump(image);
209 }
210