s390/decompressor: rework uncompressed image info collection
authorVasily Gorbik <gor@linux.ibm.com>
Thu, 19 Jul 2018 14:51:25 +0000 (16:51 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 9 Oct 2018 09:21:02 +0000 (11:21 +0200)
The kernel decompressor has to know several bits of information about
uncompressed image. Currently this info is collected by running "nm" on
uncompressed vmlinux + "sed" and producing sizes.h file. This method
worked well, but it has several disadvantages. Obscure symbols name
pattern matching is fragile. Adding new values makes pattern even
longer. Logic is spread across code and make file. Limited ability to
adjust symbols values (currently magic lma value of 0x100000 is always
subtracted). Apart from that same pieces of information (and more)
would be needed for early memory detection and features like KASLR
outside of boot/compressed/ folder where sizes.h is generated.

To overcome limitations new "struct vmlinux_info" has been introduced
to include values needed for the decompressor and the rest of the
boot code. The only static instance of vmlinux_info is produced during
vmlinux link step by filling in struct fields by the linker (like it is
done with input_data in boot/compressed/vmlinux.scr.lds.S). This way
individual values could be adjusted with all the knowledge linker has
and arithmetic it supports. Later .vmlinux.info section (which contains
struct vmlinux_info) is transplanted into the decompressor image and
dropped from uncompressed image altogether.

While doing that replace "compressed/vmlinux.scr.lds.S" linker
script (whose purpose is to rename .data section in piggy.o to
.rodata.compressed) with plain objcopy command. And simplify
decompressor's linker script.

Reviewed-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/boot/compressed/Makefile
arch/s390/boot/compressed/decompressor.h
arch/s390/boot/compressed/misc.c
arch/s390/boot/compressed/vmlinux.lds.S
arch/s390/boot/compressed/vmlinux.scr.lds.S [deleted file]
arch/s390/boot/startup.c
arch/s390/kernel/vmlinux.lds.S

index c16ded8a35bef04cb40d35e01d0efa9ae50798b0..8262984aa405baa2dee90a21feed71ed29ea971a 100644 (file)
@@ -9,13 +9,14 @@ KCOV_INSTRUMENT := n
 GCOV_PROFILE := n
 UBSAN_SANITIZE := n
 
-obj-y  := $(if $(CONFIG_KERNEL_UNCOMPRESSED),,misc.o) piggy.o
+obj-y  := $(if $(CONFIG_KERNEL_UNCOMPRESSED),,misc.o) piggy.o info.o
 targets        := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2
 targets += vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.lz4
-targets += vmlinux.scr.lds $(obj-y) $(if $(CONFIG_KERNEL_UNCOMPRESSED),,sizes.h)
+targets += info.bin $(obj-y)
 
 KBUILD_AFLAGS := $(KBUILD_AFLAGS_DECOMPRESSOR)
 KBUILD_CFLAGS := $(KBUILD_CFLAGS_DECOMPRESSOR)
+OBJCOPYFLAGS :=
 
 OBJECTS := $(addprefix $(obj)/,$(obj-y))
 
@@ -23,20 +24,16 @@ LDFLAGS_vmlinux := --oformat $(LD_BFD) -e startup -T
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(objtree)/arch/s390/boot/startup.a $(OBJECTS)
        $(call if_changed,ld)
 
-# extract required uncompressed vmlinux symbols and adjust them to reflect offsets inside vmlinux.bin
-sed-sizes := -e 's/^\([0-9a-fA-F]*\) . \(__bss_start\|_end\)$$/\#define SZ\2 (0x\1 - 0x100000)/p'
-
-quiet_cmd_sizes = GEN     $@
-      cmd_sizes = $(NM) $< | sed -n $(sed-sizes) > $@
-
-$(obj)/sizes.h: vmlinux
-       $(call if_changed,sizes)
+OBJCOPYFLAGS_info.bin := -O binary --only-section=.vmlinux.info
+$(obj)/info.bin: vmlinux FORCE
+       $(call if_changed,objcopy)
 
-CFLAGS_misc.o += -I$(objtree)/$(obj)
-$(obj)/misc.o: $(obj)/sizes.h
+OBJCOPYFLAGS_info.o := -I binary -O elf64-s390 -B s390:64-bit --rename-section .data=.vmlinux.info
+$(obj)/info.o: $(obj)/info.bin FORCE
+       $(call if_changed,objcopy)
 
-OBJCOPYFLAGS_vmlinux.bin :=  -R .comment -S
-$(obj)/vmlinux.bin: vmlinux
+OBJCOPYFLAGS_vmlinux.bin := -O binary --remove-section=.comment --remove-section=.vmlinux.info -S
+$(obj)/vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
 vmlinux.bin.all-y := $(obj)/vmlinux.bin
@@ -61,10 +58,10 @@ $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y)
 $(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y)
        $(call if_changed,xzkern)
 
-LDFLAGS_piggy.o := -r --format binary --oformat $(LD_BFD) -T
-$(obj)/piggy.o: $(obj)/vmlinux.scr.lds $(obj)/vmlinux.bin$(suffix-y)
-       $(call if_changed,ld)
+OBJCOPYFLAGS_piggy.o := -I binary -O elf64-s390 -B s390:64-bit --rename-section .data=.vmlinux.bin.compressed
+$(obj)/piggy.o: $(obj)/vmlinux.bin$(suffix-y) FORCE
+       $(call if_changed,objcopy)
 
-chkbss := $(filter-out $(obj)/misc.o $(obj)/piggy.o,$(OBJECTS))
+chkbss := $(filter-out $(obj)/misc.o $(obj)/piggy.o $(obj)/info.o,$(OBJECTS))
 chkbss-target := $(obj)/vmlinux.bin
 include $(srctree)/arch/s390/scripts/Makefile.chkbss
index 0dd0b84679c40315962d8de40c28a5e6ab405497..011cbb6e0e08ec5a80234f7e68dd61f39a0d41e5 100644 (file)
@@ -3,9 +3,18 @@
 #define BOOT_COMPRESSED_DECOMPRESSOR_H
 
 #ifdef CONFIG_KERNEL_UNCOMPRESSED
-static inline void *decompress_kernel(unsigned long *uncompressed_size) {}
+static inline void *decompress_kernel(void) {}
 #else
-void *decompress_kernel(unsigned long *uncompressed_size);
+void *decompress_kernel(void);
 #endif
 
+struct vmlinux_info {
+       unsigned long default_lma;
+       void (*entry)(void);
+       unsigned long image_size;       /* does not include .bss */
+};
+
+extern char _vmlinux_info[];
+#define vmlinux (*(struct vmlinux_info *)_vmlinux_info)
+
 #endif /* BOOT_COMPRESSED_DECOMPRESSOR_H */
index 321f6151ded95795ba02fc5027c018b5b4c168af..8b35af625aff44c37242e795b9d70c9fa6ec1175 100644 (file)
@@ -11,7 +11,6 @@
 #include <asm/page.h>
 #include <asm/sclp.h>
 #include <asm/ipl.h>
-#include "sizes.h"
 #include "decompressor.h"
 
 /*
 #define memzero(s, n) memset((s), 0, (n))
 
 /* Symbols defined by linker scripts */
-extern char input_data[];
-extern int input_len;
 extern char _end[];
 extern char _bss[], _ebss[];
+extern unsigned char _compressed_start[];
+extern unsigned char _compressed_end[];
 
 static void error(char *m);
 
@@ -83,12 +82,12 @@ static void error(char *x)
        asm volatile("lpsw %0" : : "Q" (psw));
 }
 
-void *decompress_kernel(unsigned long *uncompressed_size)
+void *decompress_kernel(void)
 {
        void *output, *kernel_end;
 
        output = (void *) ALIGN((unsigned long) _end + HEAP_SIZE, PAGE_SIZE);
-       kernel_end = output + SZ__bss_start;
+       kernel_end = output + vmlinux.image_size;
 
 #ifdef CONFIG_BLK_DEV_INITRD
        /*
@@ -111,9 +110,7 @@ void *decompress_kernel(unsigned long *uncompressed_size)
        free_mem_ptr = (unsigned long) _end;
        free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
 
-       __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error);
-       if (uncompressed_size)
-               *uncompressed_size = SZ__bss_start;
+       __decompress(_compressed_start, _compressed_end - _compressed_start,
+                    NULL, NULL, output, 0, NULL, error);
        return output;
 }
-
index b16ac8b3c439390e35fa83ccb8ba17e35d3e2901..3814810718efc638c805e42eb463a9401e3b62aa 100644 (file)
@@ -8,9 +8,6 @@ ENTRY(startup)
 
 SECTIONS
 {
-       /* Be careful parts of head_64.S assume startup_32 is at
-        * address 0.
-        */
        . = 0;
        .head.text : {
                _head = . ;
@@ -26,7 +23,7 @@ SECTIONS
        .rodata : {
                _rodata = . ;
                *(.rodata)       /* read-only data */
-               *(EXCLUDE_FILE (*piggy.o) .rodata.compressed)
+               *(.rodata.*)
                _erodata = . ;
        }
        .data : {
@@ -35,14 +32,26 @@ SECTIONS
                *(.data.*)
                _edata = . ;
        }
-       startup_continue = 0x100000;
+       /*
+        * uncompressed image info used by the decompressor it should match
+        * struct vmlinux_info. It comes from .vmlinux.info section of
+        * uncompressed vmlinux in a form of info.o
+        */
+       . = ALIGN(8);
+       .vmlinux.info : {
+               _vmlinux_info = .;
+               *(.vmlinux.info)
+       }
+
 #ifdef CONFIG_KERNEL_UNCOMPRESSED
        . = 0x100000;
 #else
        . = ALIGN(8);
 #endif
        .rodata.compressed : {
-               *(.rodata.compressed)
+               _compressed_start = .;
+               *(.vmlinux.bin.compressed)
+               _compressed_end = .;
        }
        . = ALIGN(256);
        .bss : {
diff --git a/arch/s390/boot/compressed/vmlinux.scr.lds.S b/arch/s390/boot/compressed/vmlinux.scr.lds.S
deleted file mode 100644 (file)
index ff01d18..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-SECTIONS
-{
-  .rodata.compressed : {
-#ifndef CONFIG_KERNEL_UNCOMPRESSED
-       input_len = .;
-       LONG(input_data_end - input_data) input_data = .;
-#endif
-       *(.data)
-#ifndef CONFIG_KERNEL_UNCOMPRESSED
-       output_len = . - 4;
-       input_data_end = .;
-#endif
-       }
-}
index 2a9ce355f8e69de4d4d7fccabd9a6cb7bd0531a6..474dee84d8a8cbe2d920268c9ef4d592a1be0200 100644 (file)
@@ -5,13 +5,11 @@
 
 void startup_kernel(void)
 {
-       void (*startup_continue)(void) = (void *)0x100000;
-       unsigned long uncompressed_size;
-       void *uncompressed_img;
+       void *img;
 
        if (!IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) {
-               uncompressed_img = decompress_kernel(&uncompressed_size);
-               memmove(startup_continue, uncompressed_img, uncompressed_size);
+               img = decompress_kernel();
+               memmove((void *)vmlinux.default_lma, img, vmlinux.image_size);
        }
-       startup_continue();
+       vmlinux.entry();
 }
index b43f8d33a3697de32e7c9f7dae4cbf2e7cf3bc46..4b59d1ce71242f76ef9de418374f843d128a6ef0 100644 (file)
@@ -146,6 +146,16 @@ SECTIONS
 
        _end = . ;
 
+       /*
+        * uncompressed image info used by the decompressor
+        * it should match struct vmlinux_info
+        */
+       .vmlinux.info 0 : {
+               QUAD(_stext)                    /* default_lma */
+               QUAD(startup_continue)          /* entry */
+               QUAD(__bss_start - _stext)      /* image_size */
+       }
+
        /* Debugging sections.  */
        STABS_DEBUG
        DWARF_DEBUG