]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
nios2: Add support for compressed kernel
authorLey Foon Tan <lftan@altera.com>
Tue, 10 Feb 2015 15:26:34 +0000 (23:26 +0800)
committerLey Foon Tan <lftan@altera.com>
Tue, 10 Feb 2015 15:26:34 +0000 (23:26 +0800)
Signed-off-by: Ley Foon Tan <lftan@altera.com>
arch/nios2/Kconfig
arch/nios2/boot/Makefile
arch/nios2/boot/compressed/Makefile [new file with mode: 0644]
arch/nios2/boot/compressed/console.c [new file with mode: 0644]
arch/nios2/boot/compressed/head.S [new file with mode: 0644]
arch/nios2/boot/compressed/misc.c [new file with mode: 0644]
arch/nios2/boot/compressed/vmlinux.lds.S [new file with mode: 0644]
arch/nios2/boot/compressed/vmlinux.scr [new file with mode: 0644]

index 2361acf6d2b1abb195c3f2daff5c64df88400a94..f77991ecfd8e181cbd82c1ed59dad0ae128b59b8 100644 (file)
@@ -134,6 +134,14 @@ config NIOS2_PASS_CMDLINE
          will override "Default kernel command string".
          Say N if you are unsure.
 
+config NIOS2_BOOT_LINK_OFFSET
+       hex "Link address offset for booting"
+       default "0x00500000"
+       help
+         This option allows you to set the link address offset of the zImage.
+         This can be useful if you are on a board which has a small amount of
+         memory.
+
 endmenu
 
 menu "Advanced setup"
index 59392dc0bdcb3710908497f2ad5a1784017e5098..c899876320df331ce1b897148c9bf05f4f247a0f 100644 (file)
@@ -24,6 +24,13 @@ $(obj)/vmImage: $(obj)/vmlinux.gz
        $(call if_changed,uimage)
        @$(kecho) 'Kernel: $@ is ready'
 
+$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
+       $(call if_changed,objcopy)
+       @$(kecho) 'Kernel: $@ is ready'
+
+$(obj)/compressed/vmlinux: $(obj)/vmlinux.gz FORCE
+       $(Q)$(MAKE) $(build)=$(obj)/compressed $@
+
 # Rule to build device tree blobs
 DTB_SRC := $(patsubst "%",%,$(CONFIG_NIOS2_DTB_SOURCE))
 
diff --git a/arch/nios2/boot/compressed/Makefile b/arch/nios2/boot/compressed/Makefile
new file mode 100644 (file)
index 0000000..5b0fb34
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+targets                := vmlinux head.o misc.o piggy.o vmlinux.lds
+asflags-y      :=
+
+OBJECTS = $(obj)/head.o $(obj)/misc.o
+
+LDFLAGS_vmlinux := -T
+
+$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(obj)/piggy.o FORCE
+       $(call if_changed,ld)
+       @:
+
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-littlenios2 -T
+
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/../vmlinux.gz FORCE
+       $(call if_changed,ld)
diff --git a/arch/nios2/boot/compressed/console.c b/arch/nios2/boot/compressed/console.c
new file mode 100644 (file)
index 0000000..2675e87
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ *  Copyright (C) 2008-2010 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/io.h>
+
+#if (defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE) && defined(JTAG_UART_BASE))\
+       || (defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE) && defined(UART0_BASE))
+static void *my_ioremap(unsigned long physaddr)
+{
+       return (void *)(physaddr | CONFIG_NIOS2_IO_REGION_BASE);
+}
+#endif
+
+#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE) && defined(JTAG_UART_BASE)
+
+#define ALTERA_JTAGUART_SIZE                           8
+#define ALTERA_JTAGUART_DATA_REG                       0
+#define ALTERA_JTAGUART_CONTROL_REG                    4
+#define ALTERA_JTAGUART_CONTROL_AC_MSK                 (0x00000400)
+#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK             (0xFFFF0000)
+static void *uartbase;
+
+#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
+static void jtag_putc(int ch)
+{
+       if (readl(uartbase + ALTERA_JTAGUART_CONTROL_REG) &
+               ALTERA_JTAGUART_CONTROL_WSPACE_MSK)
+               writeb(ch, uartbase + ALTERA_JTAGUART_DATA_REG);
+}
+#else
+static void jtag_putc(int ch)
+{
+       while ((readl(uartbase + ALTERA_JTAGUART_CONTROL_REG) &
+               ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0)
+               ;
+       writeb(ch, uartbase + ALTERA_JTAGUART_DATA_REG);
+}
+#endif
+
+static int putchar(int ch)
+{
+       jtag_putc(ch);
+       return ch;
+}
+
+static void console_init(void)
+{
+       uartbase = my_ioremap((unsigned long) JTAG_UART_BASE);
+       writel(ALTERA_JTAGUART_CONTROL_AC_MSK,
+               uartbase + ALTERA_JTAGUART_CONTROL_REG);
+}
+
+#elif defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE) && defined(UART0_BASE)
+
+#define ALTERA_UART_SIZE               32
+#define ALTERA_UART_TXDATA_REG         4
+#define ALTERA_UART_STATUS_REG         8
+#define ALTERA_UART_DIVISOR_REG                16
+#define ALTERA_UART_STATUS_TRDY_MSK    (0x40)
+static unsigned uartbase;
+
+static void uart_putc(int ch)
+{
+       int i;
+
+       for (i = 0; (i < 0x10000); i++) {
+               if (readw(uartbase + ALTERA_UART_STATUS_REG) &
+                       ALTERA_UART_STATUS_TRDY_MSK)
+                       break;
+       }
+       writeb(ch, uartbase + ALTERA_UART_TXDATA_REG);
+}
+
+static int putchar(int ch)
+{
+       uart_putc(ch);
+       if (ch == '\n')
+               uart_putc('\r');
+       return ch;
+}
+
+static void console_init(void)
+{
+       unsigned int baud, baudclk;
+
+       uartbase = (unsigned long) my_ioremap((unsigned long) UART0_BASE);
+       baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE;
+       baudclk = UART0_FREQ / baud;
+       writew(baudclk, uartbase + ALTERA_UART_DIVISOR_REG);
+}
+
+#else
+
+static int putchar(int ch)
+{
+       return ch;
+}
+
+static void console_init(void)
+{
+}
+
+#endif
+
+static int puts(const char *s)
+{
+       while (*s)
+               putchar(*s++);
+       return 0;
+}
diff --git a/arch/nios2/boot/compressed/head.S b/arch/nios2/boot/compressed/head.S
new file mode 100644 (file)
index 0000000..15c6c48
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * Based on arch/nios2/kernel/head.S
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+/*
+ *  This code can be loaded anywhere, eg FLASH ROM as reset vector,
+ *  as long as output does not overlap it.
+ */
+
+#include <linux/linkage.h>
+#include <asm/cache.h>
+
+       .text
+       .set noat
+ENTRY(_start)
+       wrctl   status, r0              /* disable interrupt */
+       /* invalidate all instruction cache */
+       movia   r1, NIOS2_ICACHE_SIZE
+       movui   r2, NIOS2_ICACHE_LINE_SIZE
+1:     initi   r1
+       sub     r1, r1, r2
+       bgt     r1, r0, 1b
+       /* invalidate all data cache */
+       movia   r1, NIOS2_DCACHE_SIZE
+       movui   r2, NIOS2_DCACHE_LINE_SIZE
+1:     initd   0(r1)
+       sub     r1, r1, r2
+       bgt     r1, r0, 1b
+
+       nextpc  r1                      /* Find out where we are */
+chkadr:
+       movia   r2, chkadr
+       beq     r1, r2, finish_move     /* We are running in correct address,
+                                          done */
+       /* move code, r1: src, r2: dest, r3: last dest */
+       addi    r1, r1, (_start - chkadr)       /* Source */
+       movia   r2, _start              /* Destination */
+       movia   r3, __bss_start         /* End of copy */
+1:     ldw     r8, 0(r1)               /* load a word from [r1] */
+       stw     r8, 0(r2)               /* stort a word to dest [r2] */
+       addi    r1, r1, 4               /* inc the src addr */
+       addi    r2, r2, 4               /* inc the dest addr */
+       blt     r2, r3, 1b
+       /* flush the data cache after moving */
+       movia   r1, NIOS2_DCACHE_SIZE
+       movui   r2, NIOS2_DCACHE_LINE_SIZE
+1:     flushd  0(r1)
+       sub     r1, r1, r2
+       bgt     r1, r0, 1b
+       movia   r1, finish_move
+       jmp     r1                      /* jmp to linked address */
+
+finish_move:
+       /* zero out the .bss segment (uninitialized common data) */
+       movia   r2, __bss_start         /* presume nothing is between */
+       movia   r1, _end                /* the .bss and _end. */
+1:     stb     r0, 0(r2)
+       addi    r2, r2, 1
+       bne     r1, r2, 1b
+       /*
+        * set up the stack pointer, some where higher than _end.
+        * The stack space must be greater than 32K for decompress.
+        */
+       movia   sp, 0x10000
+       add     sp, sp, r1
+       /* save args passed from u-boot, maybe */
+       addi    sp, sp, -16
+       stw     r4, 0(sp)
+       stw     r5, 4(sp)
+       stw     r6, 8(sp)
+       stw     r7, 12(sp)
+       /* decompress the kernel */
+       call    decompress_kernel
+       /* pass saved args to kernel */
+       ldw     r4, 0(sp)
+       ldw     r5, 4(sp)
+       ldw     r6, 8(sp)
+       ldw     r7, 12(sp)
+
+       /* flush all data cache after decompressing */
+       movia   r1, NIOS2_DCACHE_SIZE
+       movui   r2, NIOS2_DCACHE_LINE_SIZE
+1:     flushd  0(r1)
+       sub     r1, r1, r2
+       bgt     r1, r0, 1b
+       /* flush all instruction cache */
+       movia   r1, NIOS2_ICACHE_SIZE
+       movui   r2, NIOS2_ICACHE_LINE_SIZE
+1:     flushi  r1
+       sub     r1, r1, r2
+       bgt     r1, r0, 1b
+       flushp
+       /* jump to start real kernel */
+       movia   r1, (CONFIG_NIOS2_MEM_BASE | CONFIG_NIOS2_KERNEL_REGION_BASE)
+       jmp     r1
+
+       .balign 512
+fake_headers_as_bzImage:
+       .short  0
+       .ascii  "HdrS"
+       .short  0x0202
+       .short  0
+       .short  0
+       .byte   0x00, 0x10
+       .short  0
+       .byte   0
+       .byte   1
+       .byte   0x00, 0x80
+       .long   0
+       .long   0
diff --git a/arch/nios2/boot/compressed/misc.c b/arch/nios2/boot/compressed/misc.c
new file mode 100644 (file)
index 0000000..8437782
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Adapted for SH by Stuart Menefy, Aug 1999
+ *
+ * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000
+ *
+ * Based on arch/sh/boot/compressed/misc.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/string.h>
+
+/*
+ * gzip declarations
+ */
+#define OF(args)  args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n)          memset((s), 0, (n))
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+#define WSIZE 0x8000           /* Window size must be at least 32k, */
+                               /* and a power of two */
+
+static uch *inbuf;             /* input buffer */
+static uch window[WSIZE];      /* Sliding window buffer */
+
+static unsigned insize;        /* valid bytes in inbuf */
+static unsigned inptr; /* index of next byte to be processed in inbuf */
+static unsigned outcnt;        /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG     0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION   0x02 /* bit 1 set: continuation of multi-part gzip
+                               file */
+#define EXTRA_FIELD    0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME      0x08 /* bit 3 set: original file name present */
+#define COMMENT                0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED      0x20 /* bit 5 set: file is encrypted */
+#define RESERVED       0xC0 /* bit 6,7:   reserved */
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+#ifdef DEBUG
+#  define Assert(cond, msg) {if (!(cond)) error(msg); }
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ; }
+#  define Tracevv(x) {if (verbose > 1) fprintf x ; }
+#  define Tracec(c, x) {if (verbose && (c)) fprintf x ; }
+#  define Tracecv(c, x) {if (verbose > 1 && (c)) fprintf x ; }
+#else
+#  define Assert(cond, msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c, x)
+#  define Tracecv(c, x)
+#endif
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+
+extern char input_data[];
+extern int input_len;
+
+static long bytes_out;
+static uch *output_data;
+static unsigned long output_ptr;
+
+#include "console.c"
+
+static void error(char *m);
+
+int puts(const char *);
+
+extern int _end;
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+
+#define HEAP_SIZE                      0x10000
+
+#include "../../../../lib/inflate.c"
+
+void *memset(void *s, int c, size_t n)
+{
+       int i;
+       char *ss = (char *)s;
+
+       for (i = 0; i < n; i++)
+               ss[i] = c;
+       return s;
+}
+
+void *memcpy(void *__dest, __const void *__src, size_t __n)
+{
+       int i;
+       char *d = (char *)__dest, *s = (char *)__src;
+
+       for (i = 0; i < __n; i++)
+               d[i] = s[i];
+       return __dest;
+}
+
+/*
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+       if (insize != 0)
+               error("ran out of input data");
+
+       inbuf = input_data;
+       insize = input_len;
+       inptr = 1;
+       return inbuf[0];
+}
+
+/*
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+       ulg c = crc;    /* temporary variable */
+       unsigned n;
+       uch *in, *out, ch;
+
+       in = window;
+       out = &output_data[output_ptr];
+       for (n = 0; n < outcnt; n++) {
+               ch = *out++ = *in++;
+               c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+       }
+       crc = c;
+       bytes_out += (ulg)outcnt;
+       output_ptr += (ulg)outcnt;
+       outcnt = 0;
+}
+
+static void error(char *x)
+{
+       puts("\nERROR\n");
+       puts(x);
+       puts("\n\n -- System halted");
+
+       while (1)       /* Halt */
+               ;
+}
+
+void decompress_kernel(void)
+{
+       output_data = (void *) (CONFIG_NIOS2_MEM_BASE |
+                               CONFIG_NIOS2_KERNEL_REGION_BASE);
+       output_ptr = 0;
+       free_mem_ptr = (unsigned long)&_end;
+       free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
+       console_init();
+       makecrc();
+       puts("Uncompressing Linux... ");
+       gunzip();
+       puts("Ok, booting the kernel.\n");
+}
diff --git a/arch/nios2/boot/compressed/vmlinux.lds.S b/arch/nios2/boot/compressed/vmlinux.lds.S
new file mode 100644 (file)
index 0000000..e867b37
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <asm-generic/vmlinux.lds.h>
+
+OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2")
+
+OUTPUT_ARCH(nios)
+ENTRY(_start)  /* Defined in head.S */
+
+SECTIONS
+{
+       . = (CONFIG_NIOS2_MEM_BASE + CONFIG_NIOS2_BOOT_LINK_OFFSET) |   \
+               CONFIG_NIOS2_KERNEL_REGION_BASE;
+
+       _text = .;
+       .text : { *(.text) } = 0
+       .rodata : { *(.rodata) *(.rodata.*) }
+       _etext = .;
+
+       . = ALIGN(32 / 8);
+       .data : { *(.data) }
+       . = ALIGN(32 / 8);
+       _got = .;
+       .got : {
+               *(.got.plt)
+               *(.igot.plt)
+               *(.got)
+               *(.igot)
+       }
+       _egot = .;
+       _edata =  .;
+
+       . = ALIGN(32 / 8);
+       __bss_start = .;
+       .bss : { *(.bss) *(.sbss) }
+       . = ALIGN(32 / 8);
+       _ebss = .;
+       end = . ;
+       _end = . ;
+
+       got_len = (_egot - _got);
+}
diff --git a/arch/nios2/boot/compressed/vmlinux.scr b/arch/nios2/boot/compressed/vmlinux.scr
new file mode 100644 (file)
index 0000000..28c42f1
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+SECTIONS
+{
+       .data : {
+               input_len = .;
+               LONG(input_data_end - input_data) input_data = .;
+               *(.data)
+               . = ALIGN(4);
+               input_data_end = .;
+       }
+}