forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-11 297b60346df8beafee954a0fd7c2d64f33f3b9bc
kernel/arch/parisc/boot/compressed/misc.c
....@@ -5,6 +5,7 @@
55 */
66
77 #include <linux/uaccess.h>
8
+#include <linux/elf.h>
89 #include <asm/unaligned.h>
910 #include <asm/page.h>
1011 #include "sizes.h"
....@@ -144,14 +145,13 @@
144145
145146 void __noreturn error(char *x)
146147 {
147
- puts("\n\n");
148
- puts(x);
149
- puts("\n\n -- System halted");
148
+ if (x) puts(x);
149
+ puts("\n -- System halted\n");
150150 while (1) /* wait forever */
151151 ;
152152 }
153153
154
-static int print_hex(unsigned long num)
154
+static int print_num(unsigned long num, int base)
155155 {
156156 const char hex[] = "0123456789abcdef";
157157 char str[40];
....@@ -159,12 +159,14 @@
159159
160160 str[i--] = '\0';
161161 do {
162
- str[i--] = hex[num & 0x0f];
163
- num >>= 4;
162
+ str[i--] = hex[num % base];
163
+ num = num / base;
164164 } while (num);
165165
166
- str[i--] = 'x';
167
- str[i] = '0';
166
+ if (base == 16) {
167
+ str[i--] = 'x';
168
+ str[i] = '0';
169
+ } else i++;
168170 puts(&str[i]);
169171
170172 return 0;
....@@ -186,8 +188,9 @@
186188
187189 if (fmt[++i] == '%')
188190 goto put;
191
+ print_num(va_arg(args, unsigned long),
192
+ fmt[i] == 'x' ? 16:10);
189193 ++i;
190
- print_hex(va_arg(args, unsigned long));
191194 }
192195
193196 va_end(args);
....@@ -227,13 +230,62 @@
227230 asm ("sync");
228231 }
229232
233
+static void parse_elf(void *output)
234
+{
235
+#ifdef CONFIG_64BIT
236
+ Elf64_Ehdr ehdr;
237
+ Elf64_Phdr *phdrs, *phdr;
238
+#else
239
+ Elf32_Ehdr ehdr;
240
+ Elf32_Phdr *phdrs, *phdr;
241
+#endif
242
+ void *dest;
243
+ int i;
244
+
245
+ memcpy(&ehdr, output, sizeof(ehdr));
246
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
247
+ ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
248
+ ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
249
+ ehdr.e_ident[EI_MAG3] != ELFMAG3) {
250
+ error("Kernel is not a valid ELF file");
251
+ return;
252
+ }
253
+
254
+#ifdef DEBUG
255
+ printf("Parsing ELF... ");
256
+#endif
257
+
258
+ phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
259
+ if (!phdrs)
260
+ error("Failed to allocate space for phdrs");
261
+
262
+ memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);
263
+
264
+ for (i = 0; i < ehdr.e_phnum; i++) {
265
+ phdr = &phdrs[i];
266
+
267
+ switch (phdr->p_type) {
268
+ case PT_LOAD:
269
+ dest = (void *)((unsigned long) phdr->p_paddr &
270
+ (__PAGE_OFFSET_DEFAULT-1));
271
+ memmove(dest, output + phdr->p_offset, phdr->p_filesz);
272
+ break;
273
+ default:
274
+ break;
275
+ }
276
+ }
277
+
278
+ free(phdrs);
279
+}
280
+
230281 unsigned long decompress_kernel(unsigned int started_wide,
231282 unsigned int command_line,
232283 const unsigned int rd_start,
233284 const unsigned int rd_end)
234285 {
235286 char *output;
236
- unsigned long len, len_all;
287
+ unsigned long vmlinux_addr, vmlinux_len;
288
+ unsigned long kernel_addr, kernel_len;
237289
238290 #ifdef CONFIG_64BIT
239291 parisc_narrow_firmware = 0;
....@@ -241,27 +293,29 @@
241293
242294 set_firmware_width_unlocked();
243295
244
- putchar('U'); /* if you get this p and no more, string storage */
296
+ putchar('D'); /* if you get this D and no more, string storage */
245297 /* in $GLOBAL$ is wrong or %dp is wrong */
246
- puts("ncompressing ...\n");
298
+ puts("ecompressing Linux... ");
247299
248
- output = (char *) KERNEL_BINARY_TEXT_START;
249
- len_all = __pa(SZ_end) - __pa(SZparisc_kernel_start);
250
-
251
- if ((unsigned long) &_startcode_end > (unsigned long) output)
300
+ /* where the final bits are stored */
301
+ kernel_addr = KERNEL_BINARY_TEXT_START;
302
+ kernel_len = __pa(SZ_end) - __pa(SZparisc_kernel_start);
303
+ if ((unsigned long) &_startcode_end > kernel_addr)
252304 error("Bootcode overlaps kernel code");
253305
254
- len = get_unaligned_le32(&output_len);
255
- if (len > len_all)
256
- error("Output len too big.");
257
- else
258
- memset(&output[len], 0, len_all - len);
306
+ /*
307
+ * Calculate addr to where the vmlinux ELF file shall be decompressed.
308
+ * Assembly code in head.S positioned the stack directly behind bss, so
309
+ * leave 2 MB for the stack.
310
+ */
311
+ vmlinux_addr = (unsigned long) &_ebss + 2*1024*1024;
312
+ vmlinux_len = get_unaligned_le32(&output_len);
313
+ output = (char *) vmlinux_addr;
259314
260315 /*
261316 * Initialize free_mem_ptr and free_mem_end_ptr.
262317 */
263
- free_mem_ptr = (unsigned long) &_ebss;
264
- free_mem_ptr += 2*1024*1024; /* leave 2 MB for stack */
318
+ free_mem_ptr = vmlinux_addr + vmlinux_len;
265319
266320 /* Limit memory for bootoader to 1GB */
267321 #define ARTIFICIAL_LIMIT (1*1024*1024*1024)
....@@ -275,7 +329,18 @@
275329 free_mem_end_ptr = rd_start;
276330 #endif
277331
332
+ if (free_mem_ptr >= free_mem_end_ptr) {
333
+ int free_ram;
334
+ free_ram = (free_mem_ptr >> 20) + 1;
335
+ if (free_ram < 32)
336
+ free_ram = 32;
337
+ printf("\nKernel requires at least %d MB RAM.\n",
338
+ free_ram);
339
+ error(NULL);
340
+ }
341
+
278342 #ifdef DEBUG
343
+ printf("\n");
279344 printf("startcode_end = %x\n", &_startcode_end);
280345 printf("commandline = %x\n", command_line);
281346 printf("rd_start = %x\n", rd_start);
....@@ -287,16 +352,19 @@
287352 printf("input_data = %x\n", input_data);
288353 printf("input_len = %x\n", input_len);
289354 printf("output = %x\n", output);
290
- printf("output_len = %x\n", len);
291
- printf("output_max = %x\n", len_all);
355
+ printf("output_len = %x\n", vmlinux_len);
356
+ printf("kernel_addr = %x\n", kernel_addr);
357
+ printf("kernel_len = %x\n", kernel_len);
292358 #endif
293359
294360 __decompress(input_data, input_len, NULL, NULL,
295361 output, 0, NULL, error);
362
+ parse_elf(output);
296363
297
- flush_data_cache(output, len);
364
+ output = (char *) kernel_addr;
365
+ flush_data_cache(output, kernel_len);
298366
299
- printf("Booting kernel ...\n\n");
367
+ printf("done.\nBooting the kernel.\n");
300368
301369 return (unsigned long) output;
302370 }