aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2018-10-15 16:14:01 -0400
committerHelge Deller <deller@gmx.de>2018-10-17 02:18:01 -0400
commit34c201ae49fe9e0bf3b389da5869d810f201c740 (patch)
tree74d0bcbe8ad7befaffda4cb81429d556babf35dc
parentdb139d71c4c377c56a67ae219f120186ce9934d1 (diff)
parisc: Include compressed vmlinux file in vmlinuz boot kernel
Change the parisc vmlinuz boot code to include and process the real compressed vmlinux.gz ELF file instead of a compressed memory dump. This brings parisc in sync on how it's done on x86_64. The benefit of this change is that, e.g. for debugging purposes, one can then extract the vmlinux file out of the vmlinuz which was booted which wasn't possible before. This can be archieved with the existing scripts/extract-vmlinux script, which just needs a small tweak to prefer to extract a compressed file before trying the existing given binary. The downside of this approach is that due to the extra round of decompression/ELF processing we need more physical memory installed to be able to boot a kernel. Signed-off-by: Helge Deller <deller@gmx.de>
-rw-r--r--arch/parisc/boot/compressed/Makefile4
-rw-r--r--arch/parisc/boot/compressed/misc.c95
-rw-r--r--arch/parisc/boot/compressed/vmlinux.lds.S10
-rw-r--r--arch/parisc/include/asm/page.h12
4 files changed, 91 insertions, 30 deletions
diff --git a/arch/parisc/boot/compressed/Makefile b/arch/parisc/boot/compressed/Makefile
index 7d7e594bda36..777533cdea31 100644
--- a/arch/parisc/boot/compressed/Makefile
+++ b/arch/parisc/boot/compressed/Makefile
@@ -14,7 +14,7 @@ targets += misc.o piggy.o sizes.h head.o real2.o firmware.o
14 14
15KBUILD_CFLAGS := -D__KERNEL__ -O2 -DBOOTLOADER 15KBUILD_CFLAGS := -D__KERNEL__ -O2 -DBOOTLOADER
16KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING 16KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
17KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks 17KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks -fno-builtin-printf
18KBUILD_CFLAGS += -fno-PIE -mno-space-regs -mdisable-fpregs -Os 18KBUILD_CFLAGS += -fno-PIE -mno-space-regs -mdisable-fpregs -Os
19ifndef CONFIG_64BIT 19ifndef CONFIG_64BIT
20KBUILD_CFLAGS += -mfast-indirect-calls 20KBUILD_CFLAGS += -mfast-indirect-calls
@@ -22,7 +22,6 @@ endif
22 22
23OBJECTS += $(obj)/head.o $(obj)/real2.o $(obj)/firmware.o $(obj)/misc.o $(obj)/piggy.o 23OBJECTS += $(obj)/head.o $(obj)/real2.o $(obj)/firmware.o $(obj)/misc.o $(obj)/piggy.o
24 24
25# LDFLAGS_vmlinux := -X --whole-archive -e startup -T
26LDFLAGS_vmlinux := -X -e startup --as-needed -T 25LDFLAGS_vmlinux := -X -e startup --as-needed -T
27$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(LIBGCC) 26$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(LIBGCC)
28 $(call if_changed,ld) 27 $(call if_changed,ld)
@@ -55,7 +54,6 @@ $(obj)/misc.o: $(obj)/sizes.h
55CPPFLAGS_vmlinux.lds += -I$(objtree)/$(obj) -DBOOTLOADER 54CPPFLAGS_vmlinux.lds += -I$(objtree)/$(obj) -DBOOTLOADER
56$(obj)/vmlinux.lds: $(obj)/sizes.h 55$(obj)/vmlinux.lds: $(obj)/sizes.h
57 56
58OBJCOPYFLAGS_vmlinux.bin := -O binary -R .comment -S
59$(obj)/vmlinux.bin: vmlinux 57$(obj)/vmlinux.bin: vmlinux
60 $(call if_changed,objcopy) 58 $(call if_changed,objcopy)
61 59
diff --git a/arch/parisc/boot/compressed/misc.c b/arch/parisc/boot/compressed/misc.c
index f57118e1f6b4..2556bb181813 100644
--- a/arch/parisc/boot/compressed/misc.c
+++ b/arch/parisc/boot/compressed/misc.c
@@ -5,6 +5,7 @@
5 */ 5 */
6 6
7#include <linux/uaccess.h> 7#include <linux/uaccess.h>
8#include <linux/elf.h>
8#include <asm/unaligned.h> 9#include <asm/unaligned.h>
9#include <asm/page.h> 10#include <asm/page.h>
10#include "sizes.h" 11#include "sizes.h"
@@ -227,13 +228,62 @@ static void flush_data_cache(char *start, unsigned long length)
227 asm ("sync"); 228 asm ("sync");
228} 229}
229 230
231static void parse_elf(void *output)
232{
233#ifdef CONFIG_64BIT
234 Elf64_Ehdr ehdr;
235 Elf64_Phdr *phdrs, *phdr;
236#else
237 Elf32_Ehdr ehdr;
238 Elf32_Phdr *phdrs, *phdr;
239#endif
240 void *dest;
241 int i;
242
243 memcpy(&ehdr, output, sizeof(ehdr));
244 if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
245 ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
246 ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
247 ehdr.e_ident[EI_MAG3] != ELFMAG3) {
248 error("Kernel is not a valid ELF file");
249 return;
250 }
251
252#ifdef DEBUG
253 printf("Parsing ELF... ");
254#endif
255
256 phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
257 if (!phdrs)
258 error("Failed to allocate space for phdrs");
259
260 memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);
261
262 for (i = 0; i < ehdr.e_phnum; i++) {
263 phdr = &phdrs[i];
264
265 switch (phdr->p_type) {
266 case PT_LOAD:
267 dest = (void *)((unsigned long) phdr->p_paddr &
268 (__PAGE_OFFSET_DEFAULT-1));
269 memmove(dest, output + phdr->p_offset, phdr->p_filesz);
270 break;
271 default:
272 break;
273 }
274 }
275
276 free(phdrs);
277}
278
230unsigned long decompress_kernel(unsigned int started_wide, 279unsigned long decompress_kernel(unsigned int started_wide,
231 unsigned int command_line, 280 unsigned int command_line,
232 const unsigned int rd_start, 281 const unsigned int rd_start,
233 const unsigned int rd_end) 282 const unsigned int rd_end)
234{ 283{
235 char *output; 284 char *output;
236 unsigned long len, len_all; 285 unsigned long vmlinux_addr, vmlinux_len;
286 unsigned long kernel_addr, kernel_len;
237 287
238#ifdef CONFIG_64BIT 288#ifdef CONFIG_64BIT
239 parisc_narrow_firmware = 0; 289 parisc_narrow_firmware = 0;
@@ -241,27 +291,29 @@ unsigned long decompress_kernel(unsigned int started_wide,
241 291
242 set_firmware_width_unlocked(); 292 set_firmware_width_unlocked();
243 293
244 putchar('U'); /* if you get this p and no more, string storage */ 294 putchar('D'); /* if you get this D and no more, string storage */
245 /* in $GLOBAL$ is wrong or %dp is wrong */ 295 /* in $GLOBAL$ is wrong or %dp is wrong */
246 puts("ncompressing ...\n"); 296 puts("ecompressing Linux... ");
247
248 output = (char *) KERNEL_BINARY_TEXT_START;
249 len_all = __pa(SZ_end) - __pa(SZparisc_kernel_start);
250 297
251 if ((unsigned long) &_startcode_end > (unsigned long) output) 298 /* where the final bits are stored */
299 kernel_addr = KERNEL_BINARY_TEXT_START;
300 kernel_len = __pa(SZ_end) - __pa(SZparisc_kernel_start);
301 if ((unsigned long) &_startcode_end > kernel_addr)
252 error("Bootcode overlaps kernel code"); 302 error("Bootcode overlaps kernel code");
253 303
254 len = get_unaligned_le32(&output_len); 304 /*
255 if (len > len_all) 305 * Calculate addr to where the vmlinux ELF file shall be decompressed.
256 error("Output len too big."); 306 * Assembly code in head.S positioned the stack directly behind bss, so
257 else 307 * leave 2 MB for the stack.
258 memset(&output[len], 0, len_all - len); 308 */
309 vmlinux_addr = (unsigned long) &_ebss + 2*1024*1024;
310 vmlinux_len = get_unaligned_le32(&output_len);
311 output = (char *) vmlinux_addr;
259 312
260 /* 313 /*
261 * Initialize free_mem_ptr and free_mem_end_ptr. 314 * Initialize free_mem_ptr and free_mem_end_ptr.
262 */ 315 */
263 free_mem_ptr = (unsigned long) &_ebss; 316 free_mem_ptr = vmlinux_addr + vmlinux_len;
264 free_mem_ptr += 2*1024*1024; /* leave 2 MB for stack */
265 317
266 /* Limit memory for bootoader to 1GB */ 318 /* Limit memory for bootoader to 1GB */
267 #define ARTIFICIAL_LIMIT (1*1024*1024*1024) 319 #define ARTIFICIAL_LIMIT (1*1024*1024*1024)
@@ -275,7 +327,11 @@ unsigned long decompress_kernel(unsigned int started_wide,
275 free_mem_end_ptr = rd_start; 327 free_mem_end_ptr = rd_start;
276#endif 328#endif
277 329
330 if (free_mem_ptr >= free_mem_end_ptr)
331 error("Kernel too big for machine.");
332
278#ifdef DEBUG 333#ifdef DEBUG
334 printf("\n");
279 printf("startcode_end = %x\n", &_startcode_end); 335 printf("startcode_end = %x\n", &_startcode_end);
280 printf("commandline = %x\n", command_line); 336 printf("commandline = %x\n", command_line);
281 printf("rd_start = %x\n", rd_start); 337 printf("rd_start = %x\n", rd_start);
@@ -287,16 +343,19 @@ unsigned long decompress_kernel(unsigned int started_wide,
287 printf("input_data = %x\n", input_data); 343 printf("input_data = %x\n", input_data);
288 printf("input_len = %x\n", input_len); 344 printf("input_len = %x\n", input_len);
289 printf("output = %x\n", output); 345 printf("output = %x\n", output);
290 printf("output_len = %x\n", len); 346 printf("output_len = %x\n", vmlinux_len);
291 printf("output_max = %x\n", len_all); 347 printf("kernel_addr = %x\n", kernel_addr);
348 printf("kernel_len = %x\n", kernel_len);
292#endif 349#endif
293 350
294 __decompress(input_data, input_len, NULL, NULL, 351 __decompress(input_data, input_len, NULL, NULL,
295 output, 0, NULL, error); 352 output, 0, NULL, error);
353 parse_elf(output);
296 354
297 flush_data_cache(output, len); 355 output = (char *) kernel_addr;
356 flush_data_cache(output, kernel_len);
298 357
299 printf("Booting kernel ...\n\n"); 358 printf("done.\nBooting the kernel.\n");
300 359
301 return (unsigned long) output; 360 return (unsigned long) output;
302} 361}
diff --git a/arch/parisc/boot/compressed/vmlinux.lds.S b/arch/parisc/boot/compressed/vmlinux.lds.S
index 4ebd4e65524c..bfd7872739a3 100644
--- a/arch/parisc/boot/compressed/vmlinux.lds.S
+++ b/arch/parisc/boot/compressed/vmlinux.lds.S
@@ -42,6 +42,12 @@ SECTIONS
42#endif 42#endif
43 _startcode_end = .; 43 _startcode_end = .;
44 44
45 /* vmlinux.bin.gz is here */
46 . = ALIGN(8);
47 .rodata.compressed : {
48 *(.rodata.compressed)
49 }
50
45 /* bootloader code and data starts behind area of extracted kernel */ 51 /* bootloader code and data starts behind area of extracted kernel */
46 . = (SZ_end - SZparisc_kernel_start + KERNEL_BINARY_TEXT_START); 52 . = (SZ_end - SZparisc_kernel_start + KERNEL_BINARY_TEXT_START);
47 53
@@ -68,10 +74,6 @@ SECTIONS
68 _erodata = . ; 74 _erodata = . ;
69 } 75 }
70 . = ALIGN(8); 76 . = ALIGN(8);
71 .rodata.compressed : {
72 *(.rodata.compressed)
73 }
74 . = ALIGN(8);
75 .bss : { 77 .bss : {
76 _bss = . ; 78 _bss = . ;
77 *(.bss) 79 *(.bss)
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index af00fe9bf846..b77f49ce6220 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -117,14 +117,16 @@ extern int npmem_ranges;
117/* This governs the relationship between virtual and physical addresses. 117/* This governs the relationship between virtual and physical addresses.
118 * If you alter it, make sure to take care of our various fixed mapping 118 * If you alter it, make sure to take care of our various fixed mapping
119 * segments in fixmap.h */ 119 * segments in fixmap.h */
120#if defined(BOOTLOADER)
121#define __PAGE_OFFSET (0) /* bootloader uses physical addresses */
122#else
123#ifdef CONFIG_64BIT 120#ifdef CONFIG_64BIT
124#define __PAGE_OFFSET (0x40000000) /* 1GB */ 121#define __PAGE_OFFSET_DEFAULT (0x40000000) /* 1GB */
125#else 122#else
126#define __PAGE_OFFSET (0x10000000) /* 256MB */ 123#define __PAGE_OFFSET_DEFAULT (0x10000000) /* 256MB */
127#endif 124#endif
125
126#if defined(BOOTLOADER)
127#define __PAGE_OFFSET (0) /* bootloader uses physical addresses */
128#else
129#define __PAGE_OFFSET __PAGE_OFFSET_DEFAULT
128#endif /* BOOTLOADER */ 130#endif /* BOOTLOADER */
129 131
130#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) 132#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)