mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 02:39:48 +00:00
s390/decompressor: rework uncompressed image info collection
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>
This commit is contained in:
parent
8f75582a2f
commit
369f91c374
7 changed files with 61 additions and 56 deletions
|
@ -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'
|
||||
OBJCOPYFLAGS_info.bin := -O binary --only-section=.vmlinux.info
|
||||
$(obj)/info.bin: vmlinux FORCE
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
quiet_cmd_sizes = GEN $@
|
||||
cmd_sizes = $(NM) $< | sed -n $(sed-sizes) > $@
|
||||
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)
|
||||
|
||||
$(obj)/sizes.h: vmlinux
|
||||
$(call if_changed,sizes)
|
||||
|
||||
CFLAGS_misc.o += -I$(objtree)/$(obj)
|
||||
$(obj)/misc.o: $(obj)/sizes.h
|
||||
|
||||
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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <asm/page.h>
|
||||
#include <asm/sclp.h>
|
||||
#include <asm/ipl.h>
|
||||
#include "sizes.h"
|
||||
#include "decompressor.h"
|
||||
|
||||
/*
|
||||
|
@ -26,10 +25,10 @@
|
|||
#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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 : {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue