2005-04-17 02:20:36 +04:00
|
|
|
/*
|
|
|
|
* misc.c
|
2008-01-30 15:33:38 +03:00
|
|
|
*
|
2016-04-18 19:42:13 +03:00
|
|
|
* This is a collection of several routines used to extract the kernel
|
|
|
|
* which includes KASLR relocation, decompression, ELF parsing, and
|
|
|
|
* relocation processing. Additionally included are the screen and serial
|
|
|
|
* output functions and related debugging support functions.
|
2005-04-17 02:20:36 +04:00
|
|
|
*
|
|
|
|
* malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
|
|
|
|
* puts by Nick Holloway 1993, better puts by Martin Mares 1995
|
|
|
|
* High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
|
|
|
|
*/
|
|
|
|
|
2010-08-03 03:21:22 +04:00
|
|
|
#include "misc.h"
|
2014-03-18 23:26:38 +04:00
|
|
|
#include "../string.h"
|
2006-12-07 04:14:04 +03:00
|
|
|
|
|
|
|
/*
|
x86/KASLR: Update description for decompressor worst case size
The comment that describes the analysis for the size of the decompressor
code only took gzip into account (there are currently 6 other decompressors
that could be used). The actual z_extract_offset calculation in code was
already handling the correct maximum size, but this documentation hadn't
been updated. This updates the documentation, fixes several typos, moves
the comment to header.S, updates references, and adds a note at the end
of the decompressor include list to remind us about updating the comment
in the future.
(Instead of moving the comment to mkpiggy.c, where the calculation
is currently happening, it is being moved to header.S because
the calculations in mkpiggy.c will be removed in favor of header.S
calculations in a following patch, and it seemed like overkill to move
the giant comment twice, especially when there's already reference to
z_extract_offset in header.S.)
Signed-off-by: Baoquan He <bhe@redhat.com>
[ Rewrote changelog, cleaned up comment style, moved comments around. ]
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Borislav Petkov <bp@suse.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: H.J. Lu <hjl.tools@gmail.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Yinghai Lu <yinghai@kernel.org>
Link: http://lkml.kernel.org/r/1461185746-8017-2-git-send-email-keescook@chromium.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-04-20 23:55:42 +03:00
|
|
|
* WARNING!!
|
|
|
|
* This code is compiled with -fPIC and it is relocated dynamically at
|
|
|
|
* run time, but no relocation processing is performed. This means that
|
|
|
|
* it is not safe to place pointers in static structures.
|
2006-12-07 04:14:04 +03:00
|
|
|
*/
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2008-02-21 07:03:48 +03:00
|
|
|
#define STATIC static
|
2005-04-17 02:20:36 +04:00
|
|
|
|
|
|
|
#undef memcpy
|
2014-03-18 23:26:40 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Use a normal definition of memset() from string.c. There are already
|
|
|
|
* included header files which expect a definition of memset() and by
|
|
|
|
* the time we define memset macro, it is too late.
|
|
|
|
*/
|
|
|
|
#undef memset
|
2008-02-21 07:03:48 +03:00
|
|
|
#define memzero(s, n) memset((s), 0, (n))
|
2005-04-17 02:20:36 +04:00
|
|
|
|
|
|
|
|
|
|
|
static void error(char *m);
|
2008-02-21 02:19:10 +03:00
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
/*
|
|
|
|
* This is set up by the setup-routine at boot-time
|
|
|
|
*/
|
2016-04-18 19:42:12 +03:00
|
|
|
struct boot_params *boot_params;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2013-10-11 04:18:16 +04:00
|
|
|
memptr free_mem_ptr;
|
|
|
|
memptr free_mem_end_ptr;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2008-04-06 16:47:00 +04:00
|
|
|
static char *vidmem;
|
2005-04-17 02:20:36 +04:00
|
|
|
static int vidport;
|
|
|
|
static int lines, cols;
|
|
|
|
|
2009-01-05 00:46:17 +03:00
|
|
|
#ifdef CONFIG_KERNEL_GZIP
|
|
|
|
#include "../../../../lib/decompress_inflate.c"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_KERNEL_BZIP2
|
|
|
|
#include "../../../../lib/decompress_bunzip2.c"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_KERNEL_LZMA
|
|
|
|
#include "../../../../lib/decompress_unlzma.c"
|
|
|
|
#endif
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2011-01-13 04:01:24 +03:00
|
|
|
#ifdef CONFIG_KERNEL_XZ
|
|
|
|
#include "../../../../lib/decompress_unxz.c"
|
|
|
|
#endif
|
|
|
|
|
2010-01-09 01:42:45 +03:00
|
|
|
#ifdef CONFIG_KERNEL_LZO
|
|
|
|
#include "../../../../lib/decompress_unlzo.c"
|
|
|
|
#endif
|
|
|
|
|
2013-07-09 03:01:48 +04:00
|
|
|
#ifdef CONFIG_KERNEL_LZ4
|
|
|
|
#include "../../../../lib/decompress_unlz4.c"
|
|
|
|
#endif
|
x86/KASLR: Update description for decompressor worst case size
The comment that describes the analysis for the size of the decompressor
code only took gzip into account (there are currently 6 other decompressors
that could be used). The actual z_extract_offset calculation in code was
already handling the correct maximum size, but this documentation hadn't
been updated. This updates the documentation, fixes several typos, moves
the comment to header.S, updates references, and adds a note at the end
of the decompressor include list to remind us about updating the comment
in the future.
(Instead of moving the comment to mkpiggy.c, where the calculation
is currently happening, it is being moved to header.S because
the calculations in mkpiggy.c will be removed in favor of header.S
calculations in a following patch, and it seemed like overkill to move
the giant comment twice, especially when there's already reference to
z_extract_offset in header.S.)
Signed-off-by: Baoquan He <bhe@redhat.com>
[ Rewrote changelog, cleaned up comment style, moved comments around. ]
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Borislav Petkov <bp@suse.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: H.J. Lu <hjl.tools@gmail.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Yinghai Lu <yinghai@kernel.org>
Link: http://lkml.kernel.org/r/1461185746-8017-2-git-send-email-keescook@chromium.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-04-20 23:55:42 +03:00
|
|
|
/*
|
|
|
|
* NOTE: When adding a new decompressor, please update the analysis in
|
|
|
|
* ../header.S.
|
|
|
|
*/
|
2013-07-09 03:01:48 +04:00
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
static void scroll(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2008-02-21 02:19:10 +03:00
|
|
|
memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);
|
|
|
|
for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2)
|
2005-04-17 02:20:36 +04:00
|
|
|
vidmem[i] = ' ';
|
|
|
|
}
|
|
|
|
|
2010-08-03 03:21:22 +04:00
|
|
|
#define XMTRDY 0x20
|
|
|
|
|
|
|
|
#define TXR 0 /* Transmit register (WRITE) */
|
|
|
|
#define LSR 5 /* Line Status */
|
|
|
|
static void serial_putchar(int ch)
|
|
|
|
{
|
|
|
|
unsigned timeout = 0xffff;
|
|
|
|
|
|
|
|
while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
|
|
|
|
cpu_relax();
|
|
|
|
|
|
|
|
outb(ch, early_serial_base + TXR);
|
|
|
|
}
|
|
|
|
|
2012-07-20 05:04:39 +04:00
|
|
|
void __putstr(const char *s)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
2008-02-21 02:19:10 +03:00
|
|
|
int x, y, pos;
|
2005-04-17 02:20:36 +04:00
|
|
|
char c;
|
|
|
|
|
2010-08-03 03:21:22 +04:00
|
|
|
if (early_serial_base) {
|
|
|
|
const char *str = s;
|
|
|
|
while (*str) {
|
|
|
|
if (*str == '\n')
|
|
|
|
serial_putchar('\r');
|
|
|
|
serial_putchar(*str++);
|
|
|
|
}
|
|
|
|
}
|
2008-06-18 22:04:35 +04:00
|
|
|
|
2016-04-18 19:42:12 +03:00
|
|
|
if (boot_params->screen_info.orig_video_mode == 0 &&
|
2008-05-30 02:31:14 +04:00
|
|
|
lines == 0 && cols == 0)
|
2007-10-22 03:41:35 +04:00
|
|
|
return;
|
|
|
|
|
2016-04-18 19:42:12 +03:00
|
|
|
x = boot_params->screen_info.orig_x;
|
|
|
|
y = boot_params->screen_info.orig_y;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2008-02-21 02:19:10 +03:00
|
|
|
while ((c = *s++) != '\0') {
|
|
|
|
if (c == '\n') {
|
2005-04-17 02:20:36 +04:00
|
|
|
x = 0;
|
2008-02-21 02:19:10 +03:00
|
|
|
if (++y >= lines) {
|
2005-04-17 02:20:36 +04:00
|
|
|
scroll();
|
|
|
|
y--;
|
|
|
|
}
|
|
|
|
} else {
|
2008-08-02 23:23:36 +04:00
|
|
|
vidmem[(x + cols * y) * 2] = c;
|
2008-02-21 02:19:10 +03:00
|
|
|
if (++x >= cols) {
|
2005-04-17 02:20:36 +04:00
|
|
|
x = 0;
|
2008-02-21 02:19:10 +03:00
|
|
|
if (++y >= lines) {
|
2005-04-17 02:20:36 +04:00
|
|
|
scroll();
|
|
|
|
y--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-18 19:42:12 +03:00
|
|
|
boot_params->screen_info.orig_x = x;
|
|
|
|
boot_params->screen_info.orig_y = y;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
|
|
|
pos = (x + cols * y) * 2; /* Update cursor position */
|
2008-01-30 15:30:05 +03:00
|
|
|
outb(14, vidport);
|
|
|
|
outb(0xff & (pos >> 9), vidport+1);
|
|
|
|
outb(15, vidport);
|
|
|
|
outb(0xff & (pos >> 1), vidport+1);
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
2015-07-07 02:06:20 +03:00
|
|
|
void __puthex(unsigned long value)
|
|
|
|
{
|
|
|
|
char alpha[2] = "0";
|
|
|
|
int bits;
|
|
|
|
|
|
|
|
for (bits = sizeof(value) * 8 - 4; bits >= 0; bits -= 4) {
|
|
|
|
unsigned long digit = (value >> bits) & 0xf;
|
|
|
|
|
|
|
|
if (digit < 0xA)
|
|
|
|
alpha[0] = '0' + digit;
|
|
|
|
else
|
|
|
|
alpha[0] = 'a' + (digit - 0xA);
|
|
|
|
|
|
|
|
__putstr(alpha);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 02:20:36 +04:00
|
|
|
static void error(char *x)
|
|
|
|
{
|
2012-07-20 05:04:38 +04:00
|
|
|
error_putstr("\n\n");
|
|
|
|
error_putstr(x);
|
|
|
|
error_putstr("\n\n -- System halted");
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2008-01-30 15:32:31 +03:00
|
|
|
while (1)
|
|
|
|
asm("hlt");
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
2013-07-08 20:15:17 +04:00
|
|
|
#if CONFIG_X86_NEED_RELOCS
|
|
|
|
static void handle_relocations(void *output, unsigned long output_len)
|
|
|
|
{
|
|
|
|
int *reloc;
|
|
|
|
unsigned long delta, map, ptr;
|
|
|
|
unsigned long min_addr = (unsigned long)output;
|
|
|
|
unsigned long max_addr = min_addr + output_len;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate the delta between where vmlinux was linked to load
|
|
|
|
* and where it was actually loaded.
|
|
|
|
*/
|
|
|
|
delta = min_addr - LOAD_PHYSICAL_ADDR;
|
|
|
|
if (!delta) {
|
|
|
|
debug_putstr("No relocation needed... ");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
debug_putstr("Performing relocations... ");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The kernel contains a table of relocation addresses. Those
|
|
|
|
* addresses have the final load address of the kernel in virtual
|
|
|
|
* memory. We are currently working in the self map. So we need to
|
|
|
|
* create an adjustment for kernel memory addresses to the self map.
|
|
|
|
* This will involve subtracting out the base address of the kernel.
|
|
|
|
*/
|
|
|
|
map = delta - __START_KERNEL_map;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process relocations: 32 bit relocations first then 64 bit after.
|
2014-11-04 11:50:18 +03:00
|
|
|
* Three sets of binary relocations are added to the end of the kernel
|
2013-07-08 20:15:17 +04:00
|
|
|
* before compression. Each relocation table entry is the kernel
|
|
|
|
* address of the location which needs to be updated stored as a
|
|
|
|
* 32-bit value which is sign extended to 64 bits.
|
|
|
|
*
|
|
|
|
* Format is:
|
|
|
|
*
|
|
|
|
* kernel bits...
|
|
|
|
* 0 - zero terminator for 64 bit relocations
|
|
|
|
* 64 bit relocation repeated
|
2014-11-04 11:50:18 +03:00
|
|
|
* 0 - zero terminator for inverse 32 bit relocations
|
|
|
|
* 32 bit inverse relocation repeated
|
2013-07-08 20:15:17 +04:00
|
|
|
* 0 - zero terminator for 32 bit relocations
|
|
|
|
* 32 bit relocation repeated
|
|
|
|
*
|
|
|
|
* So we work backwards from the end of the decompressed image.
|
|
|
|
*/
|
|
|
|
for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) {
|
|
|
|
int extended = *reloc;
|
|
|
|
extended += map;
|
|
|
|
|
|
|
|
ptr = (unsigned long)extended;
|
|
|
|
if (ptr < min_addr || ptr > max_addr)
|
|
|
|
error("32-bit relocation outside of kernel!\n");
|
|
|
|
|
|
|
|
*(uint32_t *)ptr += delta;
|
|
|
|
}
|
|
|
|
#ifdef CONFIG_X86_64
|
2014-11-04 11:50:18 +03:00
|
|
|
while (*--reloc) {
|
|
|
|
long extended = *reloc;
|
|
|
|
extended += map;
|
|
|
|
|
|
|
|
ptr = (unsigned long)extended;
|
|
|
|
if (ptr < min_addr || ptr > max_addr)
|
|
|
|
error("inverse 32-bit relocation outside of kernel!\n");
|
|
|
|
|
|
|
|
*(int32_t *)ptr -= delta;
|
|
|
|
}
|
2013-07-08 20:15:17 +04:00
|
|
|
for (reloc--; *reloc; reloc--) {
|
|
|
|
long extended = *reloc;
|
|
|
|
extended += map;
|
|
|
|
|
|
|
|
ptr = (unsigned long)extended;
|
|
|
|
if (ptr < min_addr || ptr > max_addr)
|
|
|
|
error("64-bit relocation outside of kernel!\n");
|
|
|
|
|
|
|
|
*(uint64_t *)ptr += delta;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static inline void handle_relocations(void *output, unsigned long output_len)
|
|
|
|
{ }
|
|
|
|
#endif
|
|
|
|
|
2008-02-13 23:54:58 +03:00
|
|
|
static void parse_elf(void *output)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_X86_64
|
|
|
|
Elf64_Ehdr ehdr;
|
|
|
|
Elf64_Phdr *phdrs, *phdr;
|
|
|
|
#else
|
|
|
|
Elf32_Ehdr ehdr;
|
|
|
|
Elf32_Phdr *phdrs, *phdr;
|
|
|
|
#endif
|
|
|
|
void *dest;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
memcpy(&ehdr, output, sizeof(ehdr));
|
2008-02-21 02:19:10 +03:00
|
|
|
if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
|
2008-02-13 23:54:58 +03:00
|
|
|
ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
|
|
|
|
ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
|
2008-02-21 02:19:10 +03:00
|
|
|
ehdr.e_ident[EI_MAG3] != ELFMAG3) {
|
2008-02-13 23:54:58 +03:00
|
|
|
error("Kernel is not a valid ELF file");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-20 05:04:37 +04:00
|
|
|
debug_putstr("Parsing ELF... ");
|
2008-02-13 23:54:58 +03:00
|
|
|
|
|
|
|
phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
|
|
|
|
if (!phdrs)
|
|
|
|
error("Failed to allocate space for phdrs");
|
|
|
|
|
|
|
|
memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);
|
|
|
|
|
2008-02-21 02:19:10 +03:00
|
|
|
for (i = 0; i < ehdr.e_phnum; i++) {
|
2008-02-13 23:54:58 +03:00
|
|
|
phdr = &phdrs[i];
|
|
|
|
|
|
|
|
switch (phdr->p_type) {
|
|
|
|
case PT_LOAD:
|
|
|
|
#ifdef CONFIG_RELOCATABLE
|
|
|
|
dest = output;
|
|
|
|
dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR);
|
|
|
|
#else
|
2008-02-21 02:19:10 +03:00
|
|
|
dest = (void *)(phdr->p_paddr);
|
2008-02-13 23:54:58 +03:00
|
|
|
#endif
|
|
|
|
memcpy(dest,
|
|
|
|
output + phdr->p_offset,
|
|
|
|
phdr->p_filesz);
|
|
|
|
break;
|
|
|
|
default: /* Ignore other PT_* */ break;
|
|
|
|
}
|
|
|
|
}
|
2012-01-24 02:34:59 +04:00
|
|
|
|
|
|
|
free(phdrs);
|
2008-02-13 23:54:58 +03:00
|
|
|
}
|
|
|
|
|
2016-04-18 19:42:13 +03:00
|
|
|
asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
|
2008-02-21 07:03:48 +03:00
|
|
|
unsigned char *input_data,
|
|
|
|
unsigned long input_len,
|
2013-07-08 20:15:17 +04:00
|
|
|
unsigned char *output,
|
2014-10-31 16:40:38 +03:00
|
|
|
unsigned long output_len,
|
|
|
|
unsigned long run_size)
|
2005-04-17 02:20:36 +04:00
|
|
|
{
|
2015-01-16 03:51:46 +03:00
|
|
|
unsigned char *output_orig = output;
|
|
|
|
|
2016-04-18 19:42:12 +03:00
|
|
|
/* Retain x86 boot parameters pointer passed from startup_32/64. */
|
|
|
|
boot_params = rmode;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2016-04-18 19:42:12 +03:00
|
|
|
/* Clear flags intended for solely in-kernel use. */
|
|
|
|
boot_params->hdr.loadflags &= ~KASLR_FLAG;
|
2015-04-01 13:49:52 +03:00
|
|
|
|
2016-04-18 19:42:12 +03:00
|
|
|
sanitize_boot_params(boot_params);
|
2013-01-29 13:05:24 +04:00
|
|
|
|
2016-04-18 19:42:12 +03:00
|
|
|
if (boot_params->screen_info.orig_video_mode == 7) {
|
2005-04-17 02:20:36 +04:00
|
|
|
vidmem = (char *) 0xb0000;
|
|
|
|
vidport = 0x3b4;
|
|
|
|
} else {
|
|
|
|
vidmem = (char *) 0xb8000;
|
|
|
|
vidport = 0x3d4;
|
|
|
|
}
|
|
|
|
|
2016-04-18 19:42:12 +03:00
|
|
|
lines = boot_params->screen_info.orig_video_lines;
|
|
|
|
cols = boot_params->screen_info.orig_video_cols;
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2010-08-03 03:21:22 +04:00
|
|
|
console_init();
|
2016-04-18 19:42:13 +03:00
|
|
|
debug_putstr("early console in extract_kernel\n");
|
2010-08-03 03:21:22 +04:00
|
|
|
|
2008-01-30 15:33:38 +03:00
|
|
|
free_mem_ptr = heap; /* Heap */
|
2008-04-08 14:54:30 +04:00
|
|
|
free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
|
2006-12-07 04:14:04 +03:00
|
|
|
|
2015-07-07 02:06:20 +03:00
|
|
|
/* Report initial kernel position details. */
|
|
|
|
debug_putaddr(input_data);
|
|
|
|
debug_putaddr(input_len);
|
|
|
|
debug_putaddr(output);
|
|
|
|
debug_putaddr(output_len);
|
|
|
|
debug_putaddr(run_size);
|
|
|
|
|
2014-10-31 16:40:38 +03:00
|
|
|
/*
|
|
|
|
* The memory hole needed for the kernel is the larger of either
|
|
|
|
* the entire decompressed kernel plus relocation table, or the
|
|
|
|
* entire decompressed kernel plus .bss and .brk sections.
|
|
|
|
*/
|
2016-04-18 19:42:14 +03:00
|
|
|
output = choose_random_location(input_data, input_len, output,
|
2014-10-31 16:40:38 +03:00
|
|
|
output_len > run_size ? output_len
|
|
|
|
: run_size);
|
2013-10-11 04:18:14 +04:00
|
|
|
|
|
|
|
/* Validate memory location choices. */
|
2009-05-12 22:33:08 +04:00
|
|
|
if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
|
|
|
|
error("Destination address inappropriately aligned");
|
2008-01-30 15:33:38 +03:00
|
|
|
#ifdef CONFIG_X86_64
|
2009-05-12 22:33:08 +04:00
|
|
|
if (heap > 0x3fffffffffffUL)
|
2008-01-30 15:33:38 +03:00
|
|
|
error("Destination address too large");
|
|
|
|
#else
|
2010-12-17 06:11:09 +03:00
|
|
|
if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff))
|
2006-12-07 04:14:04 +03:00
|
|
|
error("Destination address too large");
|
2009-05-12 22:33:08 +04:00
|
|
|
#endif
|
2006-12-07 04:14:04 +03:00
|
|
|
#ifndef CONFIG_RELOCATABLE
|
2009-05-12 22:33:08 +04:00
|
|
|
if ((unsigned long)output != LOAD_PHYSICAL_ADDR)
|
2006-12-07 04:14:04 +03:00
|
|
|
error("Wrong destination address");
|
|
|
|
#endif
|
2005-04-17 02:20:36 +04:00
|
|
|
|
2012-07-20 05:04:37 +04:00
|
|
|
debug_putstr("\nDecompressing Linux... ");
|
2015-09-10 01:39:12 +03:00
|
|
|
__decompress(input_data, input_len, NULL, NULL, output, output_len,
|
|
|
|
NULL, error);
|
2008-02-13 23:54:58 +03:00
|
|
|
parse_elf(output);
|
2015-01-16 03:51:46 +03:00
|
|
|
/*
|
|
|
|
* 32-bit always performs relocations. 64-bit relocations are only
|
|
|
|
* needed if kASLR has chosen a different load address.
|
|
|
|
*/
|
|
|
|
if (!IS_ENABLED(CONFIG_X86_64) || output != output_orig)
|
|
|
|
handle_relocations(output, output_len);
|
2012-07-20 05:04:37 +04:00
|
|
|
debug_putstr("done.\nBooting the kernel.\n");
|
2013-10-11 04:18:14 +04:00
|
|
|
return output;
|
2005-04-17 02:20:36 +04:00
|
|
|
}
|