Commit 01623627 authored by Ley Foon Tan's avatar Ley Foon Tan

nios2: Add support for compressed kernel

Signed-off-by: default avatarLey Foon Tan <lftan@altera.com>
parent e8bf5bc7
......@@ -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"
......
......@@ -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))
......
#
# 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)
/*
* 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;
}
/*
* 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
/*
* 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");
}
/*
* 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);
}
/*
* 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 = .;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment