x86/boot: Extract error reporting functions
[cascardo/linux.git] / arch / x86 / boot / compressed / misc.c
index 0381e25..9536d77 100644 (file)
@@ -12,7 +12,9 @@
  */
 
 #include "misc.h"
+#include "error.h"
 #include "../string.h"
+#include "../voffset.h"
 
 /*
  * WARNING!!
 #undef memcpy
 #undef memset
 #define memzero(s, n)  memset((s), 0, (n))
+#define memmove                memmove
 
 /* Functions used by the included decompressor code below. */
-static void error(char *m);
+void *memmove(void *dest, const void *src, size_t n);
 
 /*
  * This is set up by the setup-routine at boot-time
@@ -80,7 +83,7 @@ static void scroll(void)
 {
        int i;
 
-       memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);
+       memmove(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);
        for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2)
                vidmem[i] = ' ';
 }
@@ -166,23 +169,13 @@ void __puthex(unsigned long value)
        }
 }
 
-static void error(char *x)
-{
-       error_putstr("\n\n");
-       error_putstr(x);
-       error_putstr("\n\n -- System halted");
-
-       while (1)
-               asm("hlt");
-}
-
 #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;
+       unsigned long max_addr = min_addr + (VO___bss_start - VO__text);
 
        /*
         * Calculate the delta between where vmlinux was linked to load
@@ -224,7 +217,7 @@ static void handle_relocations(void *output, unsigned long output_len)
         * So we work backwards from the end of the decompressed image.
         */
        for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) {
-               int extended = *reloc;
+               long extended = *reloc;
                extended += map;
 
                ptr = (unsigned long)extended;
@@ -301,9 +294,7 @@ static void parse_elf(void *output)
 #else
                        dest = (void *)(phdr->p_paddr);
 #endif
-                       memcpy(dest,
-                              output + phdr->p_offset,
-                              phdr->p_filesz);
+                       memmove(dest, output + phdr->p_offset, phdr->p_filesz);
                        break;
                default: /* Ignore other PT_* */ break;
                }
@@ -312,13 +303,30 @@ static void parse_elf(void *output)
        free(phdrs);
 }
 
+/*
+ * The compressed kernel image (ZO), has been moved so that its position
+ * is against the end of the buffer used to hold the uncompressed kernel
+ * image (VO) and the execution environment (.bss, .brk), which makes sure
+ * there is room to do the in-place decompression. (See header.S for the
+ * calculations.)
+ *
+ *                             |-----compressed kernel image------|
+ *                             V                                  V
+ * 0                       extract_offset                      +INIT_SIZE
+ * |-----------|---------------|-------------------------|--------|
+ *             |               |                         |        |
+ *           VO__text      startup_32 of ZO          VO__end    ZO__end
+ *             ^                                         ^
+ *             |-------uncompressed kernel image---------|
+ *
+ */
 asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
                                  unsigned char *input_data,
                                  unsigned long input_len,
                                  unsigned char *output,
-                                 unsigned long output_len,
-                                 unsigned long run_size)
+                                 unsigned long output_len)
 {
+       const unsigned long kernel_total_size = VO__end - VO__text;
        unsigned char *output_orig = output;
 
        /* Retain x86 boot parameters pointer passed from startup_32/64. */
@@ -351,7 +359,7 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
        debug_putaddr(input_len);
        debug_putaddr(output);
        debug_putaddr(output_len);
-       debug_putaddr(run_size);
+       debug_putaddr(kernel_total_size);
 
        /*
         * The memory hole needed for the kernel is the larger of either
@@ -359,8 +367,7 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
         * entire decompressed kernel plus .bss and .brk sections.
         */
        output = choose_random_location(input_data, input_len, output,
-                                       output_len > run_size ? output_len
-                                                             : run_size);
+                                       max(output_len, kernel_total_size));
 
        /* Validate memory location choices. */
        if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))