ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS)
else
ZTEXTADDR := 0
-ZBSSADDR := ALIGN(4)
+ZBSSADDR := ALIGN(8)
endif
SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
ccflags-y := -fpic -fno-builtin
asflags-y := -Wa,-march=all
-# Provide size of uncompressed kernel to the decompressor via a linker symbol.
-LDFLAGS_vmlinux = --defsym _image_size=$(shell stat -c "%s" $(obj)/../Image)
# Supply ZRELADDR to the decompressor via a linker symbol.
ifneq ($(CONFIG_AUTO_ZRELADDR),y)
LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
$(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S FORCE
$(call cmd,shipped)
+# We need to prevent any GOTOFF relocs being used with references
+# to symbols in the .bss section since we cannot relocate them
+# independently from the rest at run time. This can be achieved by
+# ensuring that no private .bss symbols exist, as global symbols
+# always have a GOT entry which is what we need.
+# The .data section is already discarded by the linker script so no need
+# to bother about it here.
+check_for_bad_syms = \
+bad_syms=$$($(CROSS_COMPILE)nm $@ | sed -n 's/^.\{8\} [bc] \(.*\)/\1/p') && \
+[ -z "$$bad_syms" ] || \
+ ( echo "following symbols must have non local/private scope:" >&2; \
+ echo "$$bad_syms" >&2; rm -f $@; false )
+
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
$(call if_changed,ld)
- @:
+ @$(check_for_bad_syms)
$(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE
$(call if_changed,$(suffix_y))
#include "../../../../lib/decompress_unlzma.c"
#endif
-void do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
+int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
{
- decompress(input, len, NULL, NULL, output, NULL, error);
+ return decompress(input, len, NULL, NULL, output, NULL, error);
}
bl cache_on
restart: adr r0, LC0
- ldmia r0, {r1, r2, r3, r5, r6, r9, r11, r12}
- ldr sp, [r0, #32]
+ ldmia r0, {r1, r2, r3, r6, r10, r11, r12}
+ ldr sp, [r0, #28]
/*
* We might be running at a different address. We need
* to fix up various pointers.
*/
sub r0, r0, r1 @ calculate the delta offset
- add r5, r5, r0 @ _start
add r6, r6, r0 @ _edata
+ add r10, r10, r0 @ inflated kernel size location
+
+ /*
+ * The kernel build system appends the size of the
+ * decompressed kernel at the end of the compressed data
+ * in little-endian form.
+ */
+ ldrb r9, [r10, #0]
+ ldrb lr, [r10, #1]
+ orr r9, r9, lr, lsl #8
+ ldrb lr, [r10, #2]
+ ldrb r10, [r10, #3]
+ orr r9, r9, lr, lsl #16
+ orr r9, r9, r10, lsl #24
#ifndef CONFIG_ZBOOT_ROM
/* malloc space is above the relocated stack (64k max) */
/*
* Check to see if we will overwrite ourselves.
* r4 = final kernel address
- * r5 = start of this image
* r9 = size of decompressed image
* r10 = end of this image, including bss/stack/malloc space if non XIP
* We basically want:
- * r4 >= r10 -> OK
- * r4 + image length <= r5 -> OK
+ * r4 - 16k page directory >= r10 -> OK
+ * r4 + image length <= current position (pc) -> OK
*/
+ add r10, r10, #16384
cmp r4, r10
bhs wont_overwrite
add r10, r4, r9
- cmp r10, r5
+ ARM( cmp r10, pc )
+ THUMB( mov lr, pc )
+ THUMB( cmp r10, lr )
bls wont_overwrite
/*
* Relocate ourselves past the end of the decompressed kernel.
- * r5 = start of this image
* r6 = _edata
* r10 = end of the decompressed kernel
* Because we always copy ahead, we need to do it from the end and go
* backward in case the source and destination overlap.
*/
- /* Round up to next 256-byte boundary. */
- add r10, r10, #256
+ /*
+ * Bump to the next 256-byte boundary with the size of
+ * the relocation code added. This avoids overwriting
+ * ourself when the offset is small.
+ */
+ add r10, r10, #((reloc_code_end - restart + 256) & ~255)
bic r10, r10, #255
+ /* Get start of code we want to copy and align it down. */
+ adr r5, restart
+ bic r5, r5, #31
+
sub r9, r6, r5 @ size to copy
add r9, r9, #31 @ rounded up to a multiple
bic r9, r9, #31 @ ... of 32 bytes
/* Preserve offset to relocated code. */
sub r6, r9, r6
+#ifndef CONFIG_ZBOOT_ROM
+ /* cache_clean_flush may use the stack, so relocate it */
+ add sp, sp, r6
+#endif
+
bl cache_clean_flush
adr r0, BSYM(restart)
LC0: .word LC0 @ r1
.word __bss_start @ r2
.word _end @ r3
- .word _start @ r5
.word _edata @ r6
- .word _image_size @ r9
+ .word input_data_end - 4 @ r10 (inflated size location)
.word _got_start @ r11
.word _got_end @ ip
- .word user_stack_end @ sp
+ .word .L_user_stack_end @ sp
.size LC0, . - LC0
#ifdef CONFIG_ARCH_RPC
#endif
.ltorg
+reloc_code_end:
.align
.section ".stack", "aw", %nobits
-user_stack: .space 4096
-user_stack_end:
+.L_user_stack: .space 4096
+.L_user_stack_end:
#include <linux/linkage.h>
#include <asm/string.h>
-#include <asm/unaligned.h>
-
static void putstr(const char *ptr);
extern void error(char *x);
}
/*
- * gzip delarations
+ * gzip declarations
*/
extern char input_data[];
extern char input_data_end[];
unsigned char *output_data;
-unsigned long output_ptr;
unsigned long free_mem_ptr;
unsigned long free_mem_end_ptr;
error("Attempting division by 0!");
}
-extern void do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x));
+extern int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x));
-unsigned long
+void
decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
unsigned long free_mem_ptr_end_p,
int arch_id)
{
- unsigned char *tmp;
+ int ret;
output_data = (unsigned char *)output_start;
free_mem_ptr = free_mem_ptr_p;
arch_decomp_setup();
- tmp = (unsigned char *) (((unsigned long)input_data_end) - 4);
- output_ptr = get_unaligned_le32(tmp);
-
putstr("Uncompressing Linux...");
- do_decompress(input_data, input_data_end - input_data,
- output_data, error);
- putstr(" done, booting the kernel.\n");
- return output_ptr;
+ ret = do_decompress(input_data, input_data_end - input_data,
+ output_data, error);
+ if (ret)
+ error("decompressor returned an error");
+ else
+ putstr(" done, booting the kernel.\n");
}
.bss : { *(.bss) }
_end = .;
+ . = ALIGN(8); /* the stack must be 64-bit aligned */
.stack : { *(.stack) }
.stab 0 : { *(.stab) }
#include <mach/serial.h>
-static u32 *uart;
-static u32 *uart_info = (u32 *)(DAVINCI_UART_INFO);
+u32 *uart;
/* PORT_16C550A, in polled non-fifo mode */
static void putc(char c)
static inline void set_uart_info(u32 phys, void * __iomem virt)
{
+ u32 *uart_info = (u32 *)(DAVINCI_UART_INFO);
+
uart = (u32 *)phys;
uart_info[0] = phys;
uart_info[1] = (u32)virt;
#include <linux/serial_reg.h>
#include <mach/hardware.h>
-static volatile unsigned long *UART = (unsigned long *)GEMINI_UART_BASE;
+static volatile unsigned long * const UART = (unsigned long *)GEMINI_UART_BASE;
/*
* The following code assumes the serial port has already been
#include <linux/serial_reg.h>
#include <mach/hardware.h>
-static volatile u8 *uart_base;
+volatile u8 *uart_base;
#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
#include <linux/serial_reg.h>
#include <mach/hardware.h>
-static volatile u32 *uart_base;
+volatile u32 *uart_base;
#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
#define TX_DONE (UART_LSR_TEMT|UART_LSR_THRE)
-static volatile u32* uart_base;
+volatile u32* uart_base;
static inline void putc(int c)
{
#define UART2_BASE (APB_PHYS_BASE + 0x17000)
#define UART3_BASE (APB_PHYS_BASE + 0x18000)
-static volatile unsigned long *UART;
+volatile unsigned long *UART;
static inline void putc(char c)
{
#include <asm/mach-types.h>
-static unsigned long mxs_duart_base;
+unsigned long mxs_duart_base;
#define MXS_DUART(x) (*(volatile unsigned long *)(mxs_duart_base + (x)))
/* nothing */
}
-static int timeout;
+int timeout;
static void putc_ns9360(char c, void __iomem *base)
{
#define arch_decomp_wdog()
#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
-static u32 * uart_base = (u32 *)UART0_PA;
+static u32 * const uart_base = (u32 *)UART0_PA;
static void putc(int ch)
{
#define BTUART_BASE (0x40200000)
#define STUART_BASE (0x40700000)
-static unsigned long uart_base;
-static unsigned int uart_shift;
-static unsigned int uart_is_pxa;
+unsigned long uart_base;
+unsigned int uart_shift;
+unsigned int uart_is_pxa;
static inline unsigned char uart_read(int offset)
{
#define params (params())
#ifndef STANDALONE_DEBUG
-static unsigned long video_num_cols;
-static unsigned long video_num_rows;
-static unsigned long video_x;
-static unsigned long video_y;
-static unsigned char bytes_per_char_v;
-static int white;
+unsigned long video_num_cols;
+unsigned long video_num_rows;
+unsigned long video_x;
+unsigned long video_y;
+unsigned char bytes_per_char_v;
+int white;
/*
* This does not append a newline
/* uart setup */
-static unsigned int fifo_mask;
-static unsigned int fifo_max;
+unsigned int fifo_mask;
+unsigned int fifo_max;
/* forward declerations */
/* how many bytes we allow into the FIFO at a time in FIFO mode */
#define FIFO_MAX (14)
-static unsigned long uart_base;
+unsigned long uart_base;
static __inline__ void get_uart_base(void)
{
#include <linux/amba/serial.h>
#include <mach/hardware.h>
-static u32 ux500_uart_base;
+u32 ux500_uart_base;
static void putc(const char c)
{
#define arch_decomp_wdog()
#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
-static volatile u32 * uart_base = (u32 *)UART0_PA;
+static volatile u32 * const uart_base = (u32 *)UART0_PA;
static void putc(int ch)
{
#include <asm/mach-types.h>
-static unsigned long uart_base;
+unsigned long uart_base;
#define UART(x) (*(volatile unsigned long *)(uart_base + (x)))
#define MDR1_MODE_MASK 0x07
-static volatile u8 *uart_base;
-static int uart_shift;
+volatile u8 *uart_base;
+int uart_shift;
/*
* Store the DEBUG_LL uart number into memory.
/* uart setup */
-static unsigned int fifo_mask;
-static unsigned int fifo_max;
+unsigned int fifo_mask;
+unsigned int fifo_max;
/* forward declerations */