📄 head.s
字号:
/* $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 insteadin_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 nopnotfirst: cmp.d -1, $r1 ; the end of the ptable ? beq flash_ok ; if so, the flash is validated move.d [$r3+], $r2 ; partition lengthbosse: 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 offset1: 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 nop1: not $r0 ; clear bit and.d $r0, $r22: #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_STARTflash_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 start1: 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 r0checksum: moveq 0, $r01: addu.b [$r1+], $r0 subq 1, $r2 bne 1b nop ret nop
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -