Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/cris/arch-v10/boot/Makefile b/arch/cris/arch-v10/boot/Makefile
new file mode 100644
index 0000000..fe66503
--- /dev/null
+++ b/arch/cris/arch-v10/boot/Makefile
@@ -0,0 +1,12 @@
+#
+# arch/cris/boot/Makefile
+#
+
+zImage: compressed/vmlinuz
+
+compressed/vmlinuz: $(TOPDIR)/vmlinux
+	@$(MAKE) -C compressed vmlinuz
+
+clean:
+	rm -f zImage tools/build compressed/vmlinux.out
+	@$(MAKE) -C compressed clean
diff --git a/arch/cris/arch-v10/boot/compressed/Makefile b/arch/cris/arch-v10/boot/compressed/Makefile
new file mode 100644
index 0000000..5f71c2c
--- /dev/null
+++ b/arch/cris/arch-v10/boot/compressed/Makefile
@@ -0,0 +1,40 @@
+#
+# linux/arch/etrax100/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux files and romfs
+#
+
+CC = gcc-cris -melf -I $(TOPDIR)/include
+CFLAGS = -O2
+LD = ld-cris
+OBJCOPY = objcopy-cris
+OBJCOPYFLAGS = -O binary --remove-section=.bss
+OBJECTS = head.o misc.o
+
+# files to compress
+SYSTEM = $(TOPDIR)/vmlinux.bin
+
+all: vmlinuz
+
+decompress.bin: $(OBJECTS)
+	$(LD) -T decompress.ld -o decompress.o $(OBJECTS)
+	$(OBJCOPY) $(OBJCOPYFLAGS) decompress.o decompress.bin
+# save it for mkprod in the topdir.
+	cp decompress.bin $(TOPDIR)
+
+
+vmlinuz: piggy.img decompress.bin
+	cat decompress.bin piggy.img > vmlinuz
+	rm -f piggy.img
+
+head.o: head.S
+	$(CC) -D__ASSEMBLY__ -traditional -c head.S -o head.o
+
+# gzip the kernel image
+
+piggy.img: $(SYSTEM)
+	cat $(SYSTEM) | gzip -f -9 > piggy.img
+
+clean:
+	rm -f piggy.img vmlinuz vmlinuz.o
+
diff --git a/arch/cris/arch-v10/boot/compressed/README b/arch/cris/arch-v10/boot/compressed/README
new file mode 100644
index 0000000..48b3db9
--- /dev/null
+++ b/arch/cris/arch-v10/boot/compressed/README
@@ -0,0 +1,25 @@
+Creation of the self-extracting compressed kernel image (vmlinuz)
+-----------------------------------------------------------------
+$Id: README,v 1.1 2001/12/17 13:59:27 bjornw 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-v10/boot/compressed/decompress.ld b/arch/cris/arch-v10/boot/compressed/decompress.ld
new file mode 100644
index 0000000..0b0a14f
--- /dev/null
+++ b/arch/cris/arch-v10/boot/compressed/decompress.ld
@@ -0,0 +1,29 @@
+OUTPUT_FORMAT(elf32-us-cris)
+
+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-v10/boot/compressed/head.S b/arch/cris/arch-v10/boot/compressed/head.S
new file mode 100644
index 0000000..4cbdd4b
--- /dev/null
+++ b/arch/cris/arch-v10/boot/compressed/head.S
@@ -0,0 +1,111 @@
+/*
+ *  arch/cris/boot/compressed/head.S
+ *
+ *  Copyright (C) 1999, 2001 Axis Communications AB
+ *
+ *  Code that sets up the DRAM registers, calls the
+ *  decompressor to unpack the piggybacked kernel, and jumps.
+ *
+ */
+
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/arch/sv_addr_ag.h>
+
+#define RAM_INIT_MAGIC 0x56902387
+	
+	;; Exported symbols
+	
+	.globl	_input_data
+
+	
+	.text
+
+	nop
+	di
+
+;; We need to initialze DRAM registers before we start using the DRAM
+	
+	cmp.d	RAM_INIT_MAGIC, r8	; Already initialized?
+	beq	dram_init_finished
+	nop
+	
+#include "../../lib/dram_init.S"
+	
+dram_init_finished:	
+		
+	;; Initiate the PA and PB ports
+
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0
+	move.b   r0, [R_PORT_PA_DATA]
+
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0
+	move.b   r0, [R_PORT_PA_DIR]
+
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0
+	move.b   r0, [R_PORT_PB_DATA]
+
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0
+	move.b   r0, [R_PORT_PB_DIR]
+
+	;; Setup the stack to a suitably high address.
+	;; We assume 8 MB is the minimum DRAM in an eLinux
+	;; product 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 - basse) as offset to the current PC.
+	
+basse:	move.d	pc, r5
+	and.d	0x7fffffff, r5	; strip any non-cache bit
+	subq	2, r5		; compensate for the move.d pc instr
+	move.d	r5, r0		; save for later - flash address of 'basse'
+	add.d	_edata, r5
+	sub.d	basse, r5	; r5 = flash address of '_edata'
+	
+	;; Copy text+data to DRAM
+	
+	move.d	basse, r1	; destination
+	move.d	_edata, r2	; end destination
+1:	move.w	[r0+], r3
+	move.w	r3, [r1+]
+	cmp.d	r2, r1
+	bcs	1b
+	nop
+
+	move.d	r5, [_input_data] ; 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
+	
+	;; Do the decompression and save compressed size in _inptr
+
+	jsr	_decompress_kernel
+	
+	;; Put start address of root partition in r9 so the kernel can use it
+	;; when mounting from flash
+
+	move.d	[_input_data], r9	; flash address of compressed kernel
+	add.d	[_inptr], r9		; size of compressed 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
+	
+	.data
+
+_input_data:
+	.dword	0		; used by the decompressor
+
+#include "../../lib/hw_settings.S"
diff --git a/arch/cris/arch-v10/boot/compressed/misc.c b/arch/cris/arch-v10/boot/compressed/misc.c
new file mode 100644
index 0000000..1b5e83f
--- /dev/null
+++ b/arch/cris/arch-v10/boot/compressed/misc.c
@@ -0,0 +1,273 @@
+/*
+ * misc.c
+ *
+ * $Id: misc.c,v 1.6 2003/10/27 08:04:31 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/svinto.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 void
+puts(const char *s)
+{
+#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
+	while(*s) {
+#ifdef CONFIG_ETRAX_DEBUG_PORT0
+		while(!(*R_SERIAL0_STATUS & (1 << 5))) ;
+		*R_SERIAL0_TR_DATA = *s++;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT1
+		while(!(*R_SERIAL1_STATUS & (1 << 5))) ;
+		*R_SERIAL1_TR_DATA = *s++;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT2
+		while(!(*R_SERIAL2_STATUS & (1 << 5))) ;
+		*R_SERIAL2_TR_DATA = *s++;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT3
+		while(!(*R_SERIAL3_STATUS & (1 << 5))) ;
+		*R_SERIAL3_TR_DATA = *s++;
+#endif
+	}
+#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;
+}
+
+void
+decompress_kernel()
+{
+	char revision;
+	
+	/* input_data is set in head.S */
+	inbuf = input_data;
+
+#ifdef CONFIG_ETRAX_DEBUG_PORT0
+	*R_SERIAL0_XOFF = 0;
+	*R_SERIAL0_BAUD = 0x99;
+	*R_SERIAL0_TR_CTRL = 0x40;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT1
+	*R_SERIAL1_XOFF = 0;
+	*R_SERIAL1_BAUD = 0x99;
+	*R_SERIAL1_TR_CTRL = 0x40;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT2
+	*R_GEN_CONFIG = 0x08;
+	*R_SERIAL2_XOFF = 0;
+	*R_SERIAL2_BAUD = 0x99;
+	*R_SERIAL2_TR_CTRL = 0x40;
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT3
+	*R_GEN_CONFIG = 0x100;
+	*R_SERIAL3_XOFF = 0;
+	*R_SERIAL3_BAUD = 0x99;
+	*R_SERIAL3_TR_CTRL = 0x40;
+#endif
+
+	setup_normal_output_buffer();
+
+	makecrc();
+
+	__asm__ volatile ("move vr,%0" : "=rm" (revision));
+	if (revision < 10)
+	{
+		puts("You need an ETRAX 100LX to run linux 2.6\n");
+		while(1);
+	}
+
+	puts("Uncompressing Linux...\n");
+	gunzip();
+	puts("Done. Now booting the kernel.\n");
+}
diff --git a/arch/cris/arch-v10/boot/rescue/Makefile b/arch/cris/arch-v10/boot/rescue/Makefile
new file mode 100644
index 0000000..e9f2ba2
--- /dev/null
+++ b/arch/cris/arch-v10/boot/rescue/Makefile
@@ -0,0 +1,55 @@
+#
+# Makefile for rescue code
+#
+ifndef TOPDIR
+TOPDIR = ../../../..
+endif
+CC = gcc-cris -mlinux -I $(TOPDIR)/include
+CFLAGS = -O2
+LD = gcc-cris -mlinux -nostdlib
+OBJCOPY = objcopy-cris
+OBJCOPYFLAGS = -O binary --remove-section=.bss
+
+all: rescue.bin testrescue.bin kimagerescue.bin
+
+rescue: rescue.bin
+	# do nothing
+
+rescue.bin: head.o
+	$(LD) -T rescue.ld -o rescue.o head.o
+	$(OBJCOPY) $(OBJCOPYFLAGS) rescue.o rescue.bin
+	cp rescue.bin $(TOPDIR)
+
+testrescue.bin: testrescue.o
+	$(OBJCOPY) $(OBJCOPYFLAGS) testrescue.o tr.bin
+# Pad it to 784 bytes
+	dd if=/dev/zero of=tmp2423 bs=1 count=784
+	cat tr.bin tmp2423 >testrescue_tmp.bin
+	dd if=testrescue_tmp.bin of=testrescue.bin bs=1 count=784
+	rm tr.bin tmp2423 testrescue_tmp.bin
+
+kimagerescue.bin: kimagerescue.o
+	$(OBJCOPY) $(OBJCOPYFLAGS) kimagerescue.o ktr.bin
+# Pad it to 784 bytes, that's what the rescue loader expects
+	dd if=/dev/zero of=tmp2423 bs=1 count=784
+	cat ktr.bin tmp2423 >kimagerescue_tmp.bin
+	dd if=kimagerescue_tmp.bin of=kimagerescue.bin bs=1 count=784
+	rm ktr.bin tmp2423 kimagerescue_tmp.bin
+
+head.o: head.S
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+
+testrescue.o: testrescue.S
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+
+kimagerescue.o: kimagerescue.S
+	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+
+clean:
+	rm -f *.o *.bin
+
+fastdep:
+
+modules:
+
+modules-install:
diff --git a/arch/cris/arch-v10/boot/rescue/head.S b/arch/cris/arch-v10/boot/rescue/head.S
new file mode 100644
index 0000000..8689ea9
--- /dev/null
+++ b/arch/cris/arch-v10/boot/rescue/head.S
@@ -0,0 +1,333 @@
+/* $Id: head.S,v 1.6 2003/04/09 08:12:43 pkj Exp $
+ * 
+ * Rescue code, made to reside at the beginning of the
+ * flash-memory. when it starts, it checks a partition
+ * table at the first sector after the rescue sector.
+ * the partition table was generated by the product builder
+ * script and contains offsets, lengths, types and checksums
+ * for each partition that this code should check.
+ *
+ * If any of the checksums fail, we assume the flash is so
+ * corrupt that we cant use it to boot into the ftp flash
+ * loader, and instead we initialize the serial port to
+ * receive a flash-loader and new flash image. we dont include
+ * any flash code here, but just accept a certain amount of
+ * bytes from the serial port and jump into it. the downloaded
+ * code is put in the cache.
+ *
+ * The partitiontable is designed so that it is transparent to
+ * code execution - it has a relative branch opcode in the
+ * beginning that jumps over it. each entry contains extra
+ * data so we can add stuff later.
+ *
+ * Partition table format:
+ *
+ *     Code transparency:
+ * 
+ *     2 bytes    [opcode 'nop']
+ *     2 bytes    [opcode 'di']
+ *     4 bytes    [opcode 'ba <offset>', 8-bit or 16-bit version]
+ *     2 bytes    [opcode 'nop', delay slot]
+ *
+ *     Table validation (at +10):	
+ * 
+ *     2 bytes    [magic/version word for partitiontable - 0xef, 0xbe]
+ *     2 bytes    [length of all entries plus the end marker]
+ *     4 bytes    [checksum for the partitiontable itself]
+ *
+ *     Entries, each with the following format, last has offset -1:	
+ *    
+ *        4 bytes    [offset in bytes, from start of flash]
+ *        4 bytes    [length in bytes of partition]
+ *        4 bytes    [checksum, simple longword sum]
+ *        2 bytes    [partition type]
+ *        2 bytes    [flags, only bit 0 used, ro/rw = 1/0]
+ *        16 bytes   [reserved for future use]
+ *
+ *     End marker
+ *
+ *        4 bytes    [-1]
+ * 
+ *	 10 bytes    [0, padding]
+ * 
+ * Bit 0 in flags signifies RW or RO. The rescue code only bothers
+ * to check the checksum for RO partitions, since the others will
+ * change their data without updating the checksums. A 1 in bit 0
+ * means RO, 0 means RW. That way, it is possible to set a partition
+ * in RO mode initially, and later mark it as RW, since you can always
+ * write 0's to the flash.
+ *
+ * During the wait for serial input, the status LED will flash so the
+ * user knows something went wrong.
+ * 
+ * Copyright (C) 1999, 2000, 2001, 2002, 2003 Axis Communications AB
+ */
+
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/arch/sv_addr_ag.h>
+
+	;; The partitiontable is looked for at the first sector after the boot
+	;; sector. Sector size is 65536 bytes in all flashes we use.
+		
+#define PTABLE_START CONFIG_ETRAX_PTABLE_SECTOR
+#define PTABLE_MAGIC 0xbeef
+
+	;; The normal Etrax100 on-chip boot ROM does serial boot at 0x380000f0.
+	;; That is not where we put our downloaded serial boot-code. The length is
+	;; enough for downloading code that loads the rest of itself (after
+	;; having setup the DRAM etc). It is the same length as the on-chip
+	;; ROM loads, so the same host loader can be used to load a rescued
+	;; product as well as one booted through the Etrax serial boot code.
+		
+#define CODE_START 0x40000000
+#define CODE_LENGTH 784
+
+#ifdef CONFIG_ETRAX_RESCUE_SER0
+#define SERXOFF R_SERIAL0_XOFF
+#define SERBAUD R_SERIAL0_BAUD
+#define SERRECC R_SERIAL0_REC_CTRL
+#define SERRDAT R_SERIAL0_REC_DATA
+#define SERSTAT R_SERIAL0_STATUS
+#endif
+#ifdef CONFIG_ETRAX_RESCUE_SER1
+#define SERXOFF R_SERIAL1_XOFF
+#define SERBAUD R_SERIAL1_BAUD
+#define SERRECC R_SERIAL1_REC_CTRL
+#define SERRDAT R_SERIAL1_REC_DATA
+#define SERSTAT R_SERIAL1_STATUS
+#endif
+#ifdef CONFIG_ETRAX_RESCUE_SER2
+#define SERXOFF R_SERIAL2_XOFF
+#define SERBAUD R_SERIAL2_BAUD
+#define SERRECC R_SERIAL2_REC_CTRL
+#define SERRDAT R_SERIAL2_REC_DATA
+#define SERSTAT R_SERIAL2_STATUS
+#endif	
+#ifdef CONFIG_ETRAX_RESCUE_SER3
+#define SERXOFF R_SERIAL3_XOFF
+#define SERBAUD R_SERIAL3_BAUD
+#define SERRECC R_SERIAL3_REC_CTRL
+#define SERRDAT R_SERIAL3_REC_DATA
+#define SERSTAT R_SERIAL3_STATUS
+#endif
+
+#define NOP_DI 0xf025050f
+#define RAM_INIT_MAGIC 0x56902387
+
+	.text
+	
+	;; This is the entry point of the rescue code
+	;; 0x80000000 if loaded in flash (as it should be)
+	;; since etrax actually starts at address 2 when booting from flash, we
+	;; put a nop (2 bytes) here first so we dont accidentally skip the di
+	
+	nop	
+	di
+
+	jump	in_cache	; enter cached area instead
+in_cache:	
+
+	;; first put a jump test to give a possibility of upgrading the rescue code
+	;; without erasing/reflashing the sector. we put a longword of -1 here and if
+	;; it is not -1, we jump using the value as jump target. since we can always
+	;; change 1's to 0's without erasing the sector, it is possible to add new
+	;; code after this and altering the jumptarget in an upgrade.
+
+jtcd:	move.d	[jumptarget], $r0
+	cmp.d	0xffffffff, $r0
+	beq	no_newjump
+	nop
+	
+	jump	[$r0]
+
+jumptarget:	
+	.dword	0xffffffff	; can be overwritten later to insert new code
+	
+no_newjump:
+#ifdef CONFIG_ETRAX_ETHERNET		
+	;; Start MII clock to make sure it is running when tranceiver is reset
+	move.d 0x3, $r0    ; enable = on, phy = mii_clk
+	move.d $r0, [R_NETWORK_GEN_CONFIG]
+#endif
+	
+	;; We need to setup the bus registers before we start using the DRAM
+#include "../../lib/dram_init.S"
+
+	;; we now should go through the checksum-table and check the listed
+	;; partitions for errors.
+	
+	move.d	PTABLE_START, $r3
+	move.d	[$r3], $r0
+	cmp.d	NOP_DI, $r0	; make sure the nop/di is there...
+	bne	do_rescue
+	nop
+	
+	;; skip the code transparency block (10 bytes).
+
+	addq	10, $r3
+	
+	;; check for correct magic
+	
+	move.w	[$r3+], $r0
+	cmp.w	PTABLE_MAGIC, $r0
+	bne	do_rescue	; didn't recognize - trig rescue
+	nop
+
+	;; check for correct ptable checksum
+
+	movu.w	[$r3+], $r2	; ptable length
+	move.d	$r2, $r8	; save for later, length of total ptable
+	addq	28, $r8		; account for the rest
+	move.d	[$r3+], $r4	; ptable checksum
+	move.d	$r3, $r1
+	jsr	checksum	; r1 source, r2 length, returns in r0
+
+	cmp.d	$r0, $r4
+	bne	do_rescue	; didn't match - trig rescue
+	nop
+	
+	;; ptable is ok. validate each entry.
+
+	moveq	-1, $r7
+	
+ploop:	move.d	[$r3+], $r1	; partition offset (from ptable start)
+	bne	notfirst	; check if it is the partition containing ptable
+	nop			; yes..
+	move.d	$r8, $r1	; for its checksum check, skip the ptable
+	move.d	[$r3+], $r2	; partition length
+	sub.d	$r8, $r2	; minus the ptable length
+	ba	bosse
+	nop
+notfirst:	
+	cmp.d	-1, $r1		; the end of the ptable ?
+	beq	flash_ok	;   if so, the flash is validated
+	move.d	[$r3+], $r2	; partition length
+bosse:	move.d	[$r3+], $r5	; checksum
+	move.d	[$r3+], $r4	; type and flags
+	addq	16, $r3		; skip the reserved bytes
+	btstq	16, $r4		; check ro flag
+	bpl	ploop		;   rw partition, skip validation
+	nop
+	btstq	17, $r4		; check bootable flag
+	bpl	1f
+	nop
+	move.d	$r1, $r7	; remember boot partition offset
+1:	
+
+	add.d	PTABLE_START, $r1
+	
+	jsr	checksum	; checksum the partition
+	
+	cmp.d	$r0, $r5
+	beq	ploop		; checksums matched, go to next entry
+	nop
+
+	;; otherwise fall through to the rescue code.
+	
+do_rescue:
+	;; setup port PA and PB default initial directions and data
+	;; (so we can flash LEDs, and so that DTR and others are set)
+	
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DIR, $r0
+	move.b	$r0, [R_PORT_PA_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r0
+	move.b	$r0, [R_PORT_PA_DATA]
+	
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DIR, $r0
+	move.b	$r0, [R_PORT_PB_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r0
+	move.b	$r0, [R_PORT_PB_DATA]
+
+	;; setup the serial port at 115200 baud
+	
+	moveq	0, $r0
+	move.d	$r0, [SERXOFF] 
+
+	move.b	0x99, $r0
+	move.b	$r0, [SERBAUD]		; 115.2kbaud for both transmit and receive
+
+	move.b	0x40, $r0		; rec enable
+	move.b	$r0, [SERRECC] 
+
+	moveq	0, $r1		; "timer" to clock out a LED red flash
+	move.d	CODE_START, $r3	; destination counter
+	movu.w	CODE_LENGTH, $r4; length
+	
+wait_ser:
+	addq	1, $r1
+#ifndef CONFIG_ETRAX_NO_LEDS
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r2
+#endif
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r2
+#endif
+	move.d	(1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), $r0
+	btstq	16, $r1
+	bpl	1f
+	nop
+	or.d	$r0, $r2	; set bit
+	ba	2f
+	nop
+1:	not	$r0		; clear bit
+	and.d	$r0, $r2
+2:	
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	$r2, [R_PORT_PA_DATA]	
+#endif	
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	$r2, [R_PORT_PB_DATA]	
+#endif
+#ifdef CONFIG_ETRAX_90000000_LEDS
+	move.b	$r2, [0x90000000]
+#endif
+#endif
+	
+	;; check if we got something on the serial port
+	
+	move.b	[SERSTAT], $r0
+	btstq	0, $r0		; data_avail
+	bpl	wait_ser
+	nop
+
+	;; got something - copy the byte and loop
+
+	move.b	[SERRDAT], $r0
+	move.b	$r0, [$r3+]
+	
+	subq	1, $r4		; decrease length
+	bne	wait_ser
+	nop
+
+	;; jump into downloaded code
+
+	move.d	RAM_INIT_MAGIC, $r8	; Tell next product that DRAM is initialized
+	jump	CODE_START
+
+flash_ok:
+	;; check r7, which contains either -1 or the partition to boot from
+
+	cmp.d	-1, $r7
+	bne	1f
+	nop
+	move.d	PTABLE_START, $r7; otherwise use the ptable start
+1:
+	move.d	RAM_INIT_MAGIC, $r8	; Tell next product that DRAM is initialized
+	jump	$r7		; boot!
+
+
+	;; Helper subroutines
+
+	;; Will checksum by simple addition
+	;; r1 - source
+	;; r2 - length in bytes
+	;; result will be in r0
+checksum:
+	moveq	0, $r0
+1:	addu.b	[$r1+], $r0
+	subq	1, $r2
+	bne	1b
+	nop
+	ret
+	nop
diff --git a/arch/cris/arch-v10/boot/rescue/kimagerescue.S b/arch/cris/arch-v10/boot/rescue/kimagerescue.S
new file mode 100644
index 0000000..264bf7a
--- /dev/null
+++ b/arch/cris/arch-v10/boot/rescue/kimagerescue.S
@@ -0,0 +1,144 @@
+/* $Id: kimagerescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
+ * 
+ * Rescue code to be prepended on a kimage and copied to the
+ * rescue serial port.
+ * This is called from the rescue code, it will copy received data to
+ * 4004000 and after a timeout jump to it.
+ */
+
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/sv_addr_ag.h>
+
+#define CODE_START 0x40004000
+#define CODE_LENGTH 784
+#define TIMEOUT_VALUE 1000
+	
+		
+#ifdef CONFIG_ETRAX_RESCUE_SER0
+#define SERXOFF R_SERIAL0_XOFF
+#define SERBAUD R_SERIAL0_BAUD
+#define SERRECC R_SERIAL0_REC_CTRL
+#define SERRDAT R_SERIAL0_REC_DATA
+#define SERSTAT R_SERIAL0_STATUS
+#endif
+#ifdef CONFIG_ETRAX_RESCUE_SER1
+#define SERXOFF R_SERIAL1_XOFF
+#define SERBAUD R_SERIAL1_BAUD
+#define SERRECC R_SERIAL1_REC_CTRL
+#define SERRDAT R_SERIAL1_REC_DATA
+#define SERSTAT R_SERIAL1_STATUS
+#endif
+#ifdef CONFIG_ETRAX_RESCUE_SER2
+#define SERXOFF R_SERIAL2_XOFF
+#define SERBAUD R_SERIAL2_BAUD
+#define SERRECC R_SERIAL2_REC_CTRL
+#define SERRDAT R_SERIAL2_REC_DATA
+#define SERSTAT R_SERIAL2_STATUS
+#endif	
+#ifdef CONFIG_ETRAX_RESCUE_SER3
+#define SERXOFF R_SERIAL3_XOFF
+#define SERBAUD R_SERIAL3_BAUD
+#define SERRECC R_SERIAL3_REC_CTRL
+#define SERRDAT R_SERIAL3_REC_DATA
+#define SERSTAT R_SERIAL3_STATUS
+#endif
+
+	.text
+	;; This is the entry point of the rescue code
+	;; 0x80000000 if loaded in flash (as it should be)
+	;; since etrax actually starts at address 2 when booting from flash, we
+	;; put a nop (2 bytes) here first so we dont accidentally skip the di
+	
+	nop	
+	di
+#ifndef CONFIG_SVINTO_SIM	
+	;; setup port PA and PB default initial directions and data
+	;; (so we can flash LEDs, and so that DTR and others are set)
+	
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DIR, $r0
+	move.b	$r0, [R_PORT_PA_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r0
+	move.b	$r0, [R_PORT_PA_DATA]
+	
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DIR, $r0
+	move.b	$r0, [R_PORT_PB_DIR]
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r0
+	move.b	$r0, [R_PORT_PB_DATA]
+	
+	;; We need to setup the bus registers before we start using the DRAM
+#include "../../lib/dram_init.S"
+	
+#endif
+	;; Setup the stack to a suitably high address.
+	;; We assume 8 MB is the minimum DRAM in an eLinux
+	;; product and put the sp at the top for now.
+
+	move.d	0x40800000, $sp
+	
+	;; setup the serial port at 115200 baud
+	
+	moveq	0, $r0
+	move.d	$r0, [SERXOFF] 
+
+	move.b	0x99, $r0
+	move.b	$r0, [SERBAUD]		; 115.2kbaud for both transmit and receive
+
+	move.b	0x40, $r0		; rec enable
+	move.b	$r0, [SERRECC] 
+
+
+	moveq	0, $r1		; "timer" to clock out a LED red flash
+	move.d	CODE_START, $r3	; destination counter
+	move.d	CODE_LENGTH, $r4	; length
+	move.d	TIMEOUT_VALUE, $r5	; "timeout" until jump
+
+wait_ser:
+	addq	1, $r1
+	subq	1, $r5		; decrease timeout
+	beq	jump_start	; timed out
+	nop
+#ifndef CONFIG_ETRAX_NO_LEDS
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r2
+#endif
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r2
+#endif
+	move.d	(1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), $r0
+	btstq	16, $r1
+	bpl	1f
+	nop
+	or.d	$r0, $r2		; set bit
+	ba	2f
+	nop
+1:	not	$r0		; clear bit
+	and.d	$r0, $r2
+2:	
+#ifdef CONFIG_ETRAX_PA_LEDS
+	move.b	$r2, [R_PORT_PA_DATA]
+#endif	
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	$r2, [R_PORT_PB_DATA]
+#endif
+#endif
+		
+	;; check if we got something on the serial port
+	
+	move.b	[SERSTAT], $r0
+	btstq	0, $r0		; data_avail
+	bpl	wait_ser
+	nop
+
+	;; got something - copy the byte and loop
+
+	move.b	[SERRDAT], $r0
+	move.b	$r0, [$r3+]
+	move.d	TIMEOUT_VALUE, $r5	; reset "timeout"
+	subq	1, $r4		; decrease length
+	bne	wait_ser
+	nop
+jump_start:
+	;; jump into downloaded code
+
+	jump	CODE_START
diff --git a/arch/cris/arch-v10/boot/rescue/rescue.ld b/arch/cris/arch-v10/boot/rescue/rescue.ld
new file mode 100644
index 0000000..0b52a94
--- /dev/null
+++ b/arch/cris/arch-v10/boot/rescue/rescue.ld
@@ -0,0 +1,20 @@
+MEMORY 
+	{
+	flash : ORIGIN = 0x00000000,
+	        LENGTH = 0x00100000
+	}
+
+SECTIONS
+{
+	.text :
+	{
+		stext = . ;
+		*(.text)
+		etext = . ;
+	} > flash
+	.data :
+	{
+		*(.data)
+		edata = . ;
+	} > flash
+}
diff --git a/arch/cris/arch-v10/boot/rescue/testrescue.S b/arch/cris/arch-v10/boot/rescue/testrescue.S
new file mode 100644
index 0000000..566a9f3
--- /dev/null
+++ b/arch/cris/arch-v10/boot/rescue/testrescue.S
@@ -0,0 +1,26 @@
+/* $Id: testrescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
+ *
+ * Simple testcode to download by the rescue block.
+ * Just lits some LEDs to show it was downloaded correctly.
+ * 
+ * Copyright (C) 1999 Axis Communications AB
+ */
+
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/sv_addr_ag.h>
+
+	.text
+
+	nop
+	nop
+	moveq	-1, $r2
+	move.b	$r2, [R_PORT_PA_DIR]
+	moveq	0, $r2
+	move.b	$r2, [R_PORT_PA_DATA]	
+
+endless:
+	nop
+	ba	endless
+	nop
+
+	
diff --git a/arch/cris/arch-v10/boot/tools/build.c b/arch/cris/arch-v10/boot/tools/build.c
new file mode 100644
index 0000000..2f9bbb2
--- /dev/null
+++ b/arch/cris/arch-v10/boot/tools/build.c
@@ -0,0 +1,288 @@
+/*
+ *  linux/tools/build.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * This file builds a disk-image from three different files:
+ *
+ * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
+ * - setup: 8086 machine code, sets up system parm
+ * - system: 80386 code for actual system
+ *
+ * It does some checking that all files are of the correct type, and
+ * just writes the result to stdout, removing headers and padding to
+ * the right amount. It also writes some system data to stderr.
+ */
+
+/*
+ * Changes by tytso to allow root device specification
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ * Cross compiling fixes by Gertjan van Wingerde, July 1996
+ */
+
+#include <stdio.h>	/* fprintf */
+#include <string.h>
+#include <stdlib.h>	/* contains exit */
+#include <sys/types.h>	/* unistd.h needs this */
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>	/* contains read/write */
+#include <fcntl.h>
+#include <linux/a.out.h>
+#include <errno.h>
+
+#define MINIX_HEADER 32
+
+#define N_MAGIC_OFFSET 1024
+#ifndef __BFD__
+static int GCC_HEADER = sizeof(struct exec);
+#endif
+
+#ifdef __BIG_KERNEL__
+#define SYS_SIZE 0xffff
+#else
+#define SYS_SIZE DEF_SYSSIZE
+#endif
+
+#define DEFAULT_MAJOR_ROOT 0
+#define DEFAULT_MINOR_ROOT 0
+
+/* max nr of sectors of setup: don't change unless you also change
+ * bootsect etc */
+#define SETUP_SECTS 4
+
+#define STRINGIFY(x) #x
+
+typedef union {
+	int i;
+	long l;
+	short s[2];
+	char b[4];
+} conv;
+
+long intel_long(long l)
+{
+	conv t;
+
+	t.b[0] = l & 0xff; l >>= 8;
+	t.b[1] = l & 0xff; l >>= 8;
+	t.b[2] = l & 0xff; l >>= 8;
+	t.b[3] = l & 0xff; l >>= 8;
+	return t.l;
+}
+
+int intel_int(int i)
+{
+	conv t;
+
+	t.b[0] = i & 0xff; i >>= 8;
+        t.b[1] = i & 0xff; i >>= 8;
+        t.b[2] = i & 0xff; i >>= 8;
+        t.b[3] = i & 0xff; i >>= 8;
+        return t.i;
+}
+
+short intel_short(short l)
+{
+	conv t;
+
+	t.b[0] = l & 0xff; l >>= 8;
+	t.b[1] = l & 0xff; l >>= 8;
+	return t.s[0];
+}
+
+void die(const char * str)
+{
+	fprintf(stderr,"%s\n",str);
+	exit(1);
+}
+
+void usage(void)
+{
+	die("Usage: build bootsect setup system [rootdev] [> image]");
+}
+
+int main(int argc, char ** argv)
+{
+	int i,c,id,sz,tmp_int;
+	unsigned long sys_size, tmp_long;
+	char buf[1024];
+#ifndef __BFD__
+	struct exec *ex = (struct exec *)buf;
+#endif
+	char major_root, minor_root;
+	struct stat sb;
+	unsigned char setup_sectors;
+
+	if ((argc < 4) || (argc > 5))
+		usage();
+	if (argc > 4) {
+		if (!strcmp(argv[4], "CURRENT")) {
+			if (stat("/", &sb)) {
+				perror("/");
+				die("Couldn't stat /");
+			}
+			major_root = major(sb.st_dev);
+			minor_root = minor(sb.st_dev);
+		} else if (strcmp(argv[4], "FLOPPY")) {
+			if (stat(argv[4], &sb)) {
+				perror(argv[4]);
+				die("Couldn't stat root device.");
+			}
+			major_root = major(sb.st_rdev);
+			minor_root = minor(sb.st_rdev);
+		} else {
+			major_root = 0;
+			minor_root = 0;
+		}
+	} else {
+		major_root = DEFAULT_MAJOR_ROOT;
+		minor_root = DEFAULT_MINOR_ROOT;
+	}
+	fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
+	for (i=0;i<sizeof buf; i++) buf[i]=0;
+	if ((id=open(argv[1],O_RDONLY,0))<0)
+		die("Unable to open 'boot'");
+	if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
+		die("Unable to read header of 'boot'");
+	if (((long *) buf)[0]!=intel_long(0x04100301))
+		die("Non-Minix header of 'boot'");
+	if (((long *) buf)[1]!=intel_long(MINIX_HEADER))
+		die("Non-Minix header of 'boot'");
+	if (((long *) buf)[3] != 0)
+		die("Illegal data segment in 'boot'");
+	if (((long *) buf)[4] != 0)
+		die("Illegal bss in 'boot'");
+	if (((long *) buf)[5] != 0)
+		die("Non-Minix header of 'boot'");
+	if (((long *) buf)[7] != 0)
+		die("Illegal symbol table in 'boot'");
+	i=read(id,buf,sizeof buf);
+	fprintf(stderr,"Boot sector %d bytes.\n",i);
+	if (i != 512)
+		die("Boot block must be exactly 512 bytes");
+	if ((*(unsigned short *)(buf+510)) != (unsigned short)intel_short(0xAA55))
+		die("Boot block hasn't got boot flag (0xAA55)");
+	buf[508] = (char) minor_root;
+	buf[509] = (char) major_root;	
+	i=write(1,buf,512);
+	if (i!=512)
+		die("Write call failed");
+	close (id);
+	
+	if ((id=open(argv[2],O_RDONLY,0))<0)
+		die("Unable to open 'setup'");
+	if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
+		die("Unable to read header of 'setup'");
+	if (((long *) buf)[0]!=intel_long(0x04100301))
+		die("Non-Minix header of 'setup'");
+	if (((long *) buf)[1]!=intel_long(MINIX_HEADER))
+		die("Non-Minix header of 'setup'");
+	if (((long *) buf)[3] != 0)
+		die("Illegal data segment in 'setup'");
+	if (((long *) buf)[4] != 0)
+		die("Illegal bss in 'setup'");
+	if (((long *) buf)[5] != 0)
+		die("Non-Minix header of 'setup'");
+	if (((long *) buf)[7] != 0)
+		die("Illegal symbol table in 'setup'");
+	for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
+#ifdef __BIG_KERNEL__
+	{
+		if (!i) {
+			/* Working with memcpy because of alignment constraints
+			   on Sparc - Gertjan */
+			memcpy(&tmp_long, &buf[2], sizeof(long));
+			if (tmp_long != intel_long(0x53726448) )
+				die("Wrong magic in loader header of 'setup'");
+			memcpy(&tmp_int, &buf[6], sizeof(int));
+			if (tmp_int < intel_int(0x200))
+				die("Wrong version of loader header of 'setup'");
+			buf[0x11] = 1; /* LOADED_HIGH */
+			tmp_long = intel_long(0x100000);
+			memcpy(&buf[0x14], &tmp_long, sizeof(long));  /* code32_start */
+		}
+#endif
+		if (write(1,buf,c)!=c)
+			die("Write call failed");
+#ifdef __BIG_KERNEL__
+	}
+#endif
+	if (c != 0)
+		die("read-error on 'setup'");
+	close (id);
+	setup_sectors = (unsigned char)((i + 511) / 512);
+	/* for compatibility with LILO */
+	if (setup_sectors < SETUP_SECTS)
+		setup_sectors = SETUP_SECTS;
+	fprintf(stderr,"Setup is %d bytes.\n",i);
+	for (c=0 ; c<sizeof(buf) ; c++)
+		buf[c] = '\0';
+	while (i < setup_sectors * 512) {
+		c = setup_sectors * 512 - i;
+		if (c > sizeof(buf))
+			c = sizeof(buf);
+		if (write(1,buf,c) != c)
+			die("Write call failed");
+		i += c;
+	}
+	
+	if ((id=open(argv[3],O_RDONLY,0))<0)
+		die("Unable to open 'system'");
+#ifndef __BFD__
+	if (read(id,buf,GCC_HEADER) != GCC_HEADER)
+		die("Unable to read header of 'system'");
+	if (N_MAGIC(*ex) == ZMAGIC) {
+		GCC_HEADER = N_MAGIC_OFFSET;
+		lseek(id, GCC_HEADER, SEEK_SET);
+	} else if (N_MAGIC(*ex) != QMAGIC)
+		die("Non-GCC header of 'system'");
+	fprintf(stderr,"System is %d kB (%d kB code, %d kB data and %d kB bss)\n",
+		(ex->a_text+ex->a_data+ex->a_bss)/1024,
+		ex->a_text /1024,
+		ex->a_data /1024,
+		ex->a_bss  /1024);
+	sz = N_SYMOFF(*ex) - GCC_HEADER + 4;
+#else
+	if (fstat (id, &sb)) {
+	  perror ("fstat");
+	  die ("Unable to stat 'system'");
+	}
+	sz = sb.st_size;
+	fprintf (stderr, "System is %d kB\n", sz/1024);
+#endif
+	sys_size = (sz + 15) / 16;
+	if (sys_size > SYS_SIZE)
+		die("System is too big");
+	while (sz > 0) {
+		int l, n;
+
+		l = sz;
+		if (l > sizeof(buf))
+			l = sizeof(buf);
+		if ((n=read(id, buf, l)) != l) {
+			if (n == -1) 
+				perror(argv[1]);
+			else
+				fprintf(stderr, "Unexpected EOF\n");
+			die("Can't read 'system'");
+		}
+		if (write(1, buf, l) != l)
+			die("Write failed");
+		sz -= l;
+	}
+	close(id);
+	if (lseek(1, 497, 0) == 497) {
+		if (write(1, &setup_sectors, 1) != 1)
+			die("Write of setup sectors failed");
+	}
+	if (lseek(1,500,0) == 500) {
+		buf[0] = (sys_size & 0xff);
+		buf[1] = ((sys_size >> 8) & 0xff);
+		if (write(1, buf, 2) != 2)
+			die("Write failed");
+	}
+	return(0);
+}