patch-2.4.4 linux/arch/cris/boot/rescue/head.S

Next file: linux/arch/cris/boot/rescue/kimagerescue.S
Previous file: linux/arch/cris/boot/rescue/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.3/linux/arch/cris/boot/rescue/head.S linux/arch/cris/boot/rescue/head.S
@@ -0,0 +1,323 @@
+	;; $Id: head.S,v 1.3 2001/02/14 16:57:25 larsv 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 its 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 Axis Communications AB
+
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/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 0x10000
+#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_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_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_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_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
+	
+	.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
+	;; its 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:	
+	;; 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 its 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	DEF_R_PORT_PA_DIR, r0
+	move.b	r0, [R_PORT_PA_DIR]
+	move.b	DEF_R_PORT_PA_DATA, r0
+	move.b	r0, [R_PORT_PA_DATA]
+	
+	move.b	DEF_R_PORT_PB_DIR, r0
+	move.b	r0, [R_PORT_PB_DIR]
+	move.b	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	DEF_R_PORT_PA_DATA, r2
+#endif
+#ifdef CONFIG_ETRAX_PB_LEDS
+	move.b	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
+	
+	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:	
+	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

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)