diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2005-07-28 09:30:20 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-07-28 09:30:20 +0100 |
commit | 661299d9d0437a0ff72240f3d60016ac3a361a6e (patch) | |
tree | 765512576314fc3612b503f182b9ae4e60fcf849 /arch/cris/arch-v32/boot/compressed | |
parent | 05caac585f8abd6c0113856bc8858e3ef214d8a6 (diff) | |
parent | 41c018b7ecb60b1c2c4d5dee0cd37d32a94c45af (diff) |
Merge with Linus' 2.6 tree
Diffstat (limited to 'arch/cris/arch-v32/boot/compressed')
-rw-r--r-- | arch/cris/arch-v32/boot/compressed/Makefile | 41 | ||||
-rw-r--r-- | arch/cris/arch-v32/boot/compressed/README | 25 | ||||
-rw-r--r-- | arch/cris/arch-v32/boot/compressed/decompress.ld | 30 | ||||
-rw-r--r-- | arch/cris/arch-v32/boot/compressed/head.S | 193 | ||||
-rw-r--r-- | arch/cris/arch-v32/boot/compressed/misc.c | 318 |
5 files changed, 607 insertions, 0 deletions
diff --git a/arch/cris/arch-v32/boot/compressed/Makefile b/arch/cris/arch-v32/boot/compressed/Makefile new file mode 100644 index 00000000000..9f77eda914b --- /dev/null +++ b/arch/cris/arch-v32/boot/compressed/Makefile @@ -0,0 +1,41 @@ +# +# lx25/arch/cris/arch-v32/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux files and romfs +# + +target = $(target_compressed_dir) +src = $(src_compressed_dir) + +CC = gcc-cris -mlinux -march=v32 -I $(TOPDIR)/include +CFLAGS = -O2 +LD = gcc-cris -mlinux -march=v32 -nostdlib +OBJCOPY = objcopy-cris +OBJCOPYFLAGS = -O binary --remove-section=.bss +OBJECTS = $(target)/head.o $(target)/misc.o + +# files to compress +SYSTEM = $(objtree)/vmlinux.bin + +all: vmlinuz + +$(target)/decompress.bin: $(OBJECTS) + $(LD) -T $(src)/decompress.ld -o $(target)/decompress.o $(OBJECTS) + $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/decompress.o $(target)/decompress.bin + +$(objtree)/vmlinuz: $(target) piggy.img $(target)/decompress.bin + cat $(target)/decompress.bin piggy.img > $(objtree)/vmlinuz + rm -f piggy.img + cp $(objtree)/vmlinuz $(src) + +$(target)/head.o: $(src)/head.S + $(CC) -D__ASSEMBLY__ -c $< -o $@ + +# gzip the kernel image + +piggy.img: $(SYSTEM) + cat $(SYSTEM) | gzip -f -9 > piggy.img + +clean: + rm -f piggy.img $(objtree)/vmlinuz vmlinuz.o decompress.o decompress.bin $(OBJECTS) + diff --git a/arch/cris/arch-v32/boot/compressed/README b/arch/cris/arch-v32/boot/compressed/README new file mode 100644 index 00000000000..e33691d15c5 --- /dev/null +++ b/arch/cris/arch-v32/boot/compressed/README @@ -0,0 +1,25 @@ +Creation of the self-extracting compressed kernel image (vmlinuz) +----------------------------------------------------------------- +$Id: README,v 1.1 2003/08/21 09:37:03 johana Exp $ + +This can be slightly confusing because it's a process with many steps. + +The kernel object built by the arch/etrax100/Makefile, vmlinux, is split +by that makefile into text and data binary files, vmlinux.text and +vmlinux.data. + +Those files together with a ROM filesystem can be catted together and +burned into a flash or executed directly at the DRAM origin. + +They can also be catted together and compressed with gzip, which is what +happens in this makefile. Together they make up piggy.img. + +The decompressor is built into the file decompress.o. It is turned into +the binary file decompress.bin, which is catted together with piggy.img +into the file vmlinuz. It can be executed in an arbitrary place in flash. + +Be careful - it assumes some things about free locations in DRAM. It +assumes the DRAM starts at 0x40000000 and that it is at least 8 MB, +so it puts its code at 0x40700000, and initial stack at 0x40800000. + +-Bjorn diff --git a/arch/cris/arch-v32/boot/compressed/decompress.ld b/arch/cris/arch-v32/boot/compressed/decompress.ld new file mode 100644 index 00000000000..3c837feca3a --- /dev/null +++ b/arch/cris/arch-v32/boot/compressed/decompress.ld @@ -0,0 +1,30 @@ +/*#OUTPUT_FORMAT(elf32-us-cris) */ +OUTPUT_ARCH (crisv32) + +MEMORY + { + dram : ORIGIN = 0x40700000, + LENGTH = 0x00100000 + } + +SECTIONS +{ + .text : + { + _stext = . ; + *(.text) + *(.rodata) + *(.rodata.*) + _etext = . ; + } > dram + .data : + { + *(.data) + _edata = . ; + } > dram + .bss : + { + *(.bss) + _end = ALIGN( 0x10 ) ; + } > dram +} diff --git a/arch/cris/arch-v32/boot/compressed/head.S b/arch/cris/arch-v32/boot/compressed/head.S new file mode 100644 index 00000000000..0c55b83b828 --- /dev/null +++ b/arch/cris/arch-v32/boot/compressed/head.S @@ -0,0 +1,193 @@ +/* + * Code that sets up the DRAM registers, calls the + * decompressor to unpack the piggybacked kernel, and jumps. + * + * Copyright (C) 1999 - 2003, Axis Communications AB + */ + +#include <linux/config.h> +#define ASSEMBLER_MACROS_ONLY +#include <asm/arch/hwregs/asm/reg_map_asm.h> +#include <asm/arch/hwregs/asm/gio_defs_asm.h> +#include <asm/arch/hwregs/asm/config_defs_asm.h> + +#define RAM_INIT_MAGIC 0x56902387 +#define COMMAND_LINE_MAGIC 0x87109563 + + ;; Exported symbols + + .globl input_data + + .text +start: + di + + ;; Start clocks for used blocks. + move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1 + move.d [$r1], $r0 + or.d REG_STATE(config, rw_clk_ctrl, cpu, yes) | \ + REG_STATE(config, rw_clk_ctrl, bif, yes) | \ + REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0 + move.d $r0, [$r1] + + ;; If booting from NAND flash we first have to copy some + ;; data from NAND flash to internal RAM to get the code + ;; that initializes the SDRAM. Lets copy 20 KB. This + ;; code executes at 0x38010000 if booting from NAND and + ;; we are guaranted that at least 0x200 bytes are good so + ;; lets start from there. The first 8192 bytes in the nand + ;; flash is spliced with zeroes and is thus 16384 bytes. + move.d 0x38010200, $r10 + move.d 0x14200, $r11 ; Start offset in NAND flash 0x10200 + 16384 + move.d 0x5000, $r12 ; Length of copy + + ;; Before this code the tools add a partitiontable so the PC + ;; has an offset from the linked address. +offset1: + lapcq ., $r13 ; get PC + add.d first_copy_complete-offset1, $r13 + +#include "../../lib/nand_init.S" + +first_copy_complete: + ;; Initialze the DRAM registers. + cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? + beq dram_init_finished + nop + +#include "../../lib/dram_init.S" + +dram_init_finished: + lapcq ., $r13 ; get PC + add.d second_copy_complete-dram_init_finished, $r13 + + move.d REG_ADDR(config, regi_config, r_bootsel), $r0 + move.d [$r0], $r0 + and.d REG_MASK(config, r_bootsel, boot_mode), $r0 + cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0 + bne second_copy_complete ; No NAND boot + nop + + ;; Copy 2MB from NAND flash to SDRAM (at 2-4MB into the SDRAM) + move.d 0x40204000, $r10 + move.d 0x8000, $r11 + move.d 0x200000, $r12 + ba copy_nand_to_ram + nop +second_copy_complete: + + ;; Initiate the PA port. + move.d CONFIG_ETRAX_DEF_GIO_PA_OUT, $r0 + move.d REG_ADDR(gio, regi_gio, rw_pa_dout), $r1 + move.d $r0, [$r1] + + move.d CONFIG_ETRAX_DEF_GIO_PA_OE, $r0 + move.d REG_ADDR(gio, regi_gio, rw_pa_oe), $r1 + move.d $r0, [$r1] + + ;; Setup the stack to a suitably high address. + ;; We assume 8 MB is the minimum DRAM and put + ;; the SP at the top for now. + + move.d 0x40800000, $sp + + ;; Figure out where the compressed piggyback image is + ;; in the flash (since we wont try to copy it to DRAM + ;; before unpacking). It is at _edata, but in flash. + ;; Use (_edata - herami) as offset to the current PC. + + move.d REG_ADDR(config, regi_config, r_bootsel), $r0 + move.d [$r0], $r0 + and.d REG_MASK(config, r_bootsel, boot_mode), $r0 + cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0 + beq hereami2 + nop +hereami: + lapcq ., $r5 ; get PC + and.d 0x7fffffff, $r5 ; strip any non-cache bit + move.d $r5, $r0 ; save for later - flash address of 'herami' + add.d _edata, $r5 + sub.d hereami, $r5 ; r5 = flash address of '_edata' + move.d hereami, $r1 ; destination + ba 2f + nop +hereami2: + lapcq ., $r5 ; get PC + and.d 0x00ffffff, $r5 ; strip any non-cache bit + move.d $r5, $r6 + or.d 0x40200000, $r6 + move.d $r6, $r0 ; save for later - flash address of 'herami' + add.d _edata, $r5 + sub.d hereami2, $r5 ; r5 = flash address of '_edata' + add.d 0x40200000, $r5 + move.d hereami2, $r1 ; destination +2: + ;; Copy text+data to DRAM + + move.d _edata, $r2 ; end destination +1: move.w [$r0+], $r3 + move.w $r3, [$r1+] + cmp.d $r2, $r1 + bcs 1b + nop + + move.d input_data, $r0 ; for the decompressor + move.d $r5, [$r0] ; for the decompressor + + ;; Clear the decompressors BSS (between _edata and _end) + + moveq 0, $r0 + move.d _edata, $r1 + move.d _end, $r2 +1: move.w $r0, [$r1+] + cmp.d $r2, $r1 + bcs 1b + nop + + ;; Save command line magic and address. + move.d _cmd_line_magic, $r12 + move.d $r10, [$r12] + move.d _cmd_line_addr, $r12 + move.d $r11, [$r12] + + ;; Do the decompression and save compressed size in _inptr + + jsr decompress_kernel + nop + + ;; Restore command line magic and address. + move.d _cmd_line_magic, $r10 + move.d [$r10], $r10 + move.d _cmd_line_addr, $r11 + move.d [$r11], $r11 + + ;; Put start address of root partition in r9 so the kernel can use it + ;; when mounting from flash + move.d input_data, $r0 + move.d [$r0], $r9 ; flash address of compressed kernel + move.d inptr, $r0 + add.d [$r0], $r9 ; size of compressed kernel + cmp.d 0x40200000, $r9 + blo enter_kernel + nop + sub.d 0x40200000, $r9 + add.d 0x4000, $r9 + +enter_kernel: + ;; Enter the decompressed kernel + move.d RAM_INIT_MAGIC, $r8 ; Tell kernel that DRAM is initialized + jump 0x40004000 ; kernel is linked to this address + nop + + .data + +input_data: + .dword 0 ; used by the decompressor +_cmd_line_magic: + .dword 0 +_cmd_line_addr: + .dword 0 +is_nand_boot: + .dword 0 + +#include "../../lib/hw_settings.S" diff --git a/arch/cris/arch-v32/boot/compressed/misc.c b/arch/cris/arch-v32/boot/compressed/misc.c new file mode 100644 index 00000000000..54644238ed5 --- /dev/null +++ b/arch/cris/arch-v32/boot/compressed/misc.c @@ -0,0 +1,318 @@ +/* + * misc.c + * + * $Id: misc.c,v 1.8 2005/04/24 18:34:29 starvik Exp $ + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * puts by Nick Holloway 1993, better puts by Martin Mares 1995 + * adoptation for Linux/CRIS Axis Communications AB, 1999 + * + */ + +/* where the piggybacked kernel image expects itself to live. + * it is the same address we use when we network load an uncompressed + * image into DRAM, and it is the address the kernel is linked to live + * at by vmlinux.lds.S + */ + +#define KERNEL_LOAD_ADR 0x40004000 + +#include <linux/config.h> + +#include <linux/types.h> +#include <asm/arch/hwregs/reg_rdwr.h> +#include <asm/arch/hwregs/reg_map.h> +#include <asm/arch/hwregs/ser_defs.h> + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +void* memset(void* s, int c, size_t n); +void* memcpy(void* __dest, __const void* __src, + size_t __n); + +#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 */ + +unsigned inptr = 0; /* index of next byte to be processed in inbuf + * After decompression it will contain the + * compressed size, and head.S will read it. + */ + +static unsigned outcnt = 0; /* 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() inbuf[inptr++] + +/* Diagnostic functions */ +#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); +static void gzip_mark(void **); +static void gzip_release(void **); + +extern char *input_data; /* lives in head.S */ + +static long bytes_out = 0; +static uch *output_data; +static unsigned long output_ptr = 0; + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +static void puts(const char *); + +/* the "heap" is put directly after the BSS ends, at end */ + +extern int _end; +static long free_mem_ptr = (long)&_end; + +#include "../../../../../lib/inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +/* decompressor info and error messages to serial console */ + +static inline void +serout(const char *s, reg_scope_instances regi_ser) +{ + reg_ser_rs_stat_din rs; + reg_ser_rw_dout dout = {.data = *s}; + + do { + rs = REG_RD(ser, regi_ser, rs_stat_din); + } + while (!rs.tr_rdy);/* Wait for tranceiver. */ + + REG_WR(ser, regi_ser, rw_dout, dout); +} + +static void +puts(const char *s) +{ +#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL + while (*s) { +#ifdef CONFIG_ETRAX_DEBUG_PORT0 + serout(s, regi_ser0); +#endif +#ifdef CONFIG_ETRAX_DEBUG_PORT1 + serout(s, regi_ser1); +#endif +#ifdef CONFIG_ETRAX_DEBUG_PORT2 + serout(s, regi_ser2); +#endif +#ifdef CONFIG_ETRAX_DEBUG_PORT3 + serout(s, regi_ser3); +#endif + *s++; + } +/* CONFIG_ETRAX_DEBUG_PORT_NULL */ +#endif +} + +void* +memset(void* s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i<n;i++) ss[i] = c; +} + +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]; +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ + +static void +flush_window() +{ + 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("\n\n"); + puts(x); + puts("\n\n -- System halted\n"); + + while(1); /* Halt */ +} + +void +setup_normal_output_buffer() +{ + output_data = (char *)KERNEL_LOAD_ADR; +} + +static inline void +serial_setup(reg_scope_instances regi_ser) +{ + reg_ser_rw_xoff xoff; + reg_ser_rw_tr_ctrl tr_ctrl; + reg_ser_rw_rec_ctrl rec_ctrl; + reg_ser_rw_tr_baud_div tr_baud; + reg_ser_rw_rec_baud_div rec_baud; + + /* Turn off XOFF. */ + xoff = REG_RD(ser, regi_ser, rw_xoff); + + xoff.chr = 0; + xoff.automatic = regk_ser_no; + + REG_WR(ser, regi_ser, rw_xoff, xoff); + + /* Set baudrate and stopbits. */ + tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl); + rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl); + tr_baud = REG_RD(ser, regi_ser, rw_tr_baud_div); + rec_baud = REG_RD(ser, regi_ser, rw_rec_baud_div); + + tr_ctrl.stop_bits = 1; /* 2 stop bits. */ + + /* + * The baudrate setup is a bit fishy, but in the end the tranceiver is + * set to 4800 and the receiver to 115200. The magic value is + * 29.493 MHz. + */ + tr_ctrl.base_freq = regk_ser_f29_493; + rec_ctrl.base_freq = regk_ser_f29_493; + tr_baud.div = (29493000 / 8) / 4800; + rec_baud.div = (29493000 / 8) / 115200; + + REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl); + REG_WR(ser, regi_ser, rw_tr_baud_div, tr_baud); + REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl); + REG_WR(ser, regi_ser, rw_rec_baud_div, rec_baud); +} + +void +decompress_kernel() +{ + char revision; + + /* input_data is set in head.S */ + inbuf = input_data; + +#ifdef CONFIG_ETRAX_DEBUG_PORT0 + serial_setup(regi_ser0); +#endif +#ifdef CONFIG_ETRAX_DEBUG_PORT1 + serial_setup(regi_ser1); +#endif +#ifdef CONFIG_ETRAX_DEBUG_PORT2 + serial_setup(regi_ser2); +#endif +#ifdef CONFIG_ETRAX_DEBUG_PORT3 + serial_setup(regi_ser3); +#endif + + setup_normal_output_buffer(); + + makecrc(); + + __asm__ volatile ("move $vr,%0" : "=rm" (revision)); + if (revision < 32) + { + puts("You need an ETRAX FS to run Linux 2.6/crisv32.\n"); + while(1); + } + + puts("Uncompressing Linux...\n"); + gunzip(); + puts("Done. Now booting the kernel.\n"); +} |