nios2: Add support for compressed kernel
Signed-off-by: Ley Foon Tan <lftan@altera.com>
This commit is contained in:
Родитель
e8bf5bc776
Коммит
01623627a2
|
@ -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))
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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");
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 = .;
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче