Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+91 -30
+1 -3
arch/parisc/boot/compressed/Makefile
··· 14 14 15 15 KBUILD_CFLAGS := -D__KERNEL__ -O2 -DBOOTLOADER 16 16 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING 17 - KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks 17 + KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks -fno-builtin-printf 18 18 KBUILD_CFLAGS += -fno-PIE -mno-space-regs -mdisable-fpregs -Os 19 19 ifndef CONFIG_64BIT 20 20 KBUILD_CFLAGS += -mfast-indirect-calls ··· 22 22 23 23 OBJECTS += $(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 26 25 LDFLAGS_vmlinux := -X -e startup --as-needed -T 27 26 $(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(LIBGCC) 28 27 $(call if_changed,ld) ··· 54 55 CPPFLAGS_vmlinux.lds += -I$(objtree)/$(obj) -DBOOTLOADER 55 56 $(obj)/vmlinux.lds: $(obj)/sizes.h 56 57 57 - OBJCOPYFLAGS_vmlinux.bin := -O binary -R .comment -S 58 58 $(obj)/vmlinux.bin: vmlinux 59 59 $(call if_changed,objcopy) 60 60
+77 -18
arch/parisc/boot/compressed/misc.c
··· 5 5 */ 6 6 7 7 #include <linux/uaccess.h> 8 + #include <linux/elf.h> 8 9 #include <asm/unaligned.h> 9 10 #include <asm/page.h> 10 11 #include "sizes.h" ··· 228 227 asm ("sync"); 229 228 } 230 229 230 + static void parse_elf(void *output) 231 + { 232 + #ifdef CONFIG_64BIT 233 + Elf64_Ehdr ehdr; 234 + Elf64_Phdr *phdrs, *phdr; 235 + #else 236 + Elf32_Ehdr ehdr; 237 + Elf32_Phdr *phdrs, *phdr; 238 + #endif 239 + void *dest; 240 + int i; 241 + 242 + memcpy(&ehdr, output, sizeof(ehdr)); 243 + if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || 244 + ehdr.e_ident[EI_MAG1] != ELFMAG1 || 245 + ehdr.e_ident[EI_MAG2] != ELFMAG2 || 246 + ehdr.e_ident[EI_MAG3] != ELFMAG3) { 247 + error("Kernel is not a valid ELF file"); 248 + return; 249 + } 250 + 251 + #ifdef DEBUG 252 + printf("Parsing ELF... "); 253 + #endif 254 + 255 + phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum); 256 + if (!phdrs) 257 + error("Failed to allocate space for phdrs"); 258 + 259 + memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum); 260 + 261 + for (i = 0; i < ehdr.e_phnum; i++) { 262 + phdr = &phdrs[i]; 263 + 264 + switch (phdr->p_type) { 265 + case PT_LOAD: 266 + dest = (void *)((unsigned long) phdr->p_paddr & 267 + (__PAGE_OFFSET_DEFAULT-1)); 268 + memmove(dest, output + phdr->p_offset, phdr->p_filesz); 269 + break; 270 + default: 271 + break; 272 + } 273 + } 274 + 275 + free(phdrs); 276 + } 277 + 231 278 unsigned long decompress_kernel(unsigned int started_wide, 232 279 unsigned int command_line, 233 280 const unsigned int rd_start, 234 281 const unsigned int rd_end) 235 282 { 236 283 char *output; 237 - unsigned long len, len_all; 284 + unsigned long vmlinux_addr, vmlinux_len; 285 + unsigned long kernel_addr, kernel_len; 238 286 239 287 #ifdef CONFIG_64BIT 240 288 parisc_narrow_firmware = 0; ··· 291 241 292 242 set_firmware_width_unlocked(); 293 243 294 - putchar('U'); /* if you get this p and no more, string storage */ 244 + putchar('D'); /* if you get this D and no more, string storage */ 295 245 /* in $GLOBAL$ is wrong or %dp is wrong */ 296 - puts("ncompressing ...\n"); 246 + puts("ecompressing Linux... "); 297 247 298 - output = (char *) KERNEL_BINARY_TEXT_START; 299 - len_all = __pa(SZ_end) - __pa(SZparisc_kernel_start); 300 - 301 - if ((unsigned long) &_startcode_end > (unsigned long) output) 248 + /* where the final bits are stored */ 249 + kernel_addr = KERNEL_BINARY_TEXT_START; 250 + kernel_len = __pa(SZ_end) - __pa(SZparisc_kernel_start); 251 + if ((unsigned long) &_startcode_end > kernel_addr) 302 252 error("Bootcode overlaps kernel code"); 303 253 304 - len = get_unaligned_le32(&output_len); 305 - if (len > len_all) 306 - error("Output len too big."); 307 - else 308 - memset(&output[len], 0, len_all - len); 254 + /* 255 + * Calculate addr to where the vmlinux ELF file shall be decompressed. 256 + * Assembly code in head.S positioned the stack directly behind bss, so 257 + * leave 2 MB for the stack. 258 + */ 259 + vmlinux_addr = (unsigned long) &_ebss + 2*1024*1024; 260 + vmlinux_len = get_unaligned_le32(&output_len); 261 + output = (char *) vmlinux_addr; 309 262 310 263 /* 311 264 * Initialize free_mem_ptr and free_mem_end_ptr. 312 265 */ 313 - free_mem_ptr = (unsigned long) &_ebss; 314 - free_mem_ptr += 2*1024*1024; /* leave 2 MB for stack */ 266 + free_mem_ptr = vmlinux_addr + vmlinux_len; 315 267 316 268 /* Limit memory for bootoader to 1GB */ 317 269 #define ARTIFICIAL_LIMIT (1*1024*1024*1024) ··· 327 275 free_mem_end_ptr = rd_start; 328 276 #endif 329 277 278 + if (free_mem_ptr >= free_mem_end_ptr) 279 + error("Kernel too big for machine."); 280 + 330 281 #ifdef DEBUG 282 + printf("\n"); 331 283 printf("startcode_end = %x\n", &_startcode_end); 332 284 printf("commandline = %x\n", command_line); 333 285 printf("rd_start = %x\n", rd_start); ··· 343 287 printf("input_data = %x\n", input_data); 344 288 printf("input_len = %x\n", input_len); 345 289 printf("output = %x\n", output); 346 - printf("output_len = %x\n", len); 347 - printf("output_max = %x\n", len_all); 290 + printf("output_len = %x\n", vmlinux_len); 291 + printf("kernel_addr = %x\n", kernel_addr); 292 + printf("kernel_len = %x\n", kernel_len); 348 293 #endif 349 294 350 295 __decompress(input_data, input_len, NULL, NULL, 351 296 output, 0, NULL, error); 297 + parse_elf(output); 352 298 353 - flush_data_cache(output, len); 299 + output = (char *) kernel_addr; 300 + flush_data_cache(output, kernel_len); 354 301 355 - printf("Booting kernel ...\n\n"); 302 + printf("done.\nBooting the kernel.\n"); 356 303 357 304 return (unsigned long) output; 358 305 }
+6 -4
arch/parisc/boot/compressed/vmlinux.lds.S
··· 42 42 #endif 43 43 _startcode_end = .; 44 44 45 + /* vmlinux.bin.gz is here */ 46 + . = ALIGN(8); 47 + .rodata.compressed : { 48 + *(.rodata.compressed) 49 + } 50 + 45 51 /* bootloader code and data starts behind area of extracted kernel */ 46 52 . = (SZ_end - SZparisc_kernel_start + KERNEL_BINARY_TEXT_START); 47 53 ··· 72 66 *(.rodata) /* read-only data */ 73 67 *(.rodata.*) 74 68 _erodata = . ; 75 - } 76 - . = ALIGN(8); 77 - .rodata.compressed : { 78 - *(.rodata.compressed) 79 69 } 80 70 . = ALIGN(8); 81 71 .bss : {
+7 -5
arch/parisc/include/asm/page.h
··· 117 117 /* This governs the relationship between virtual and physical addresses. 118 118 * If you alter it, make sure to take care of our various fixed mapping 119 119 * segments in fixmap.h */ 120 - #if defined(BOOTLOADER) 121 - #define __PAGE_OFFSET (0) /* bootloader uses physical addresses */ 122 - #else 123 120 #ifdef CONFIG_64BIT 124 - #define __PAGE_OFFSET (0x40000000) /* 1GB */ 121 + #define __PAGE_OFFSET_DEFAULT (0x40000000) /* 1GB */ 125 122 #else 126 - #define __PAGE_OFFSET (0x10000000) /* 256MB */ 123 + #define __PAGE_OFFSET_DEFAULT (0x10000000) /* 256MB */ 127 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 130 #endif /* BOOTLOADER */ 129 131 130 132 #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)