Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | /* $Id: head.S,v 1.8 2001/10/03 17:15:15 bjornw 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,2001 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 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 ;; 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 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 |