forked from Minki/linux
369f91c374
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>
117 lines
2.5 KiB
C
117 lines
2.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Definitions and wrapper functions for kernel decompressor
|
|
*
|
|
* Copyright IBM Corp. 2010
|
|
*
|
|
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
|
|
*/
|
|
|
|
#include <linux/uaccess.h>
|
|
#include <asm/page.h>
|
|
#include <asm/sclp.h>
|
|
#include <asm/ipl.h>
|
|
#include "decompressor.h"
|
|
|
|
/*
|
|
* gzip declarations
|
|
*/
|
|
#define STATIC static
|
|
|
|
#undef memset
|
|
#undef memcpy
|
|
#undef memmove
|
|
#define memmove memmove
|
|
#define memzero(s, n) memset((s), 0, (n))
|
|
|
|
/* Symbols defined by linker scripts */
|
|
extern char _end[];
|
|
extern char _bss[], _ebss[];
|
|
extern unsigned char _compressed_start[];
|
|
extern unsigned char _compressed_end[];
|
|
|
|
static void error(char *m);
|
|
|
|
static unsigned long free_mem_ptr;
|
|
static unsigned long free_mem_end_ptr;
|
|
|
|
#ifdef CONFIG_HAVE_KERNEL_BZIP2
|
|
#define HEAP_SIZE 0x400000
|
|
#else
|
|
#define HEAP_SIZE 0x10000
|
|
#endif
|
|
|
|
#ifdef CONFIG_KERNEL_GZIP
|
|
#include "../../../../lib/decompress_inflate.c"
|
|
#endif
|
|
|
|
#ifdef CONFIG_KERNEL_BZIP2
|
|
#include "../../../../lib/decompress_bunzip2.c"
|
|
#endif
|
|
|
|
#ifdef CONFIG_KERNEL_LZ4
|
|
#include "../../../../lib/decompress_unlz4.c"
|
|
#endif
|
|
|
|
#ifdef CONFIG_KERNEL_LZMA
|
|
#include "../../../../lib/decompress_unlzma.c"
|
|
#endif
|
|
|
|
#ifdef CONFIG_KERNEL_LZO
|
|
#include "../../../../lib/decompress_unlzo.c"
|
|
#endif
|
|
|
|
#ifdef CONFIG_KERNEL_XZ
|
|
#include "../../../../lib/decompress_unxz.c"
|
|
#endif
|
|
|
|
static int puts(const char *s)
|
|
{
|
|
sclp_early_printk(s);
|
|
return 0;
|
|
}
|
|
|
|
static void error(char *x)
|
|
{
|
|
unsigned long long psw = 0x000a0000deadbeefULL;
|
|
|
|
puts("\n\n");
|
|
puts(x);
|
|
puts("\n\n -- System halted");
|
|
|
|
asm volatile("lpsw %0" : : "Q" (psw));
|
|
}
|
|
|
|
void *decompress_kernel(void)
|
|
{
|
|
void *output, *kernel_end;
|
|
|
|
output = (void *) ALIGN((unsigned long) _end + HEAP_SIZE, PAGE_SIZE);
|
|
kernel_end = output + vmlinux.image_size;
|
|
|
|
#ifdef CONFIG_BLK_DEV_INITRD
|
|
/*
|
|
* Move the initrd right behind the end of the decompressed
|
|
* kernel image. This also prevents initrd corruption caused by
|
|
* bss clearing since kernel_end will always be located behind the
|
|
* current bss section..
|
|
*/
|
|
if (INITRD_START && INITRD_SIZE && kernel_end > (void *) INITRD_START) {
|
|
memmove(kernel_end, (void *) INITRD_START, INITRD_SIZE);
|
|
INITRD_START = (unsigned long) kernel_end;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Clear bss section. free_mem_ptr and free_mem_end_ptr need to be
|
|
* initialized afterwards since they reside in bss.
|
|
*/
|
|
memset(_bss, 0, _ebss - _bss);
|
|
free_mem_ptr = (unsigned long) _end;
|
|
free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
|
|
|
|
__decompress(_compressed_start, _compressed_end - _compressed_start,
|
|
NULL, NULL, output, 0, NULL, error);
|
|
return output;
|
|
}
|