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 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | /*
* 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 can't 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-2007 Axis Communications AB
*/
#ifdef CONFIG_ETRAX_AXISFLASHMAP
#define ASSEMBLER_MACROS_ONLY
#include <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 "../../../arch-v10/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 KEEPKCONFIGIDENTS__I, $__r0
move.b $r0, [R_PORT_PA_DIR]
move.b KEEPKCONFIGIDENTS__J, $__r0
move.b $r0, [R_PORT_PA_DATA]
move.b KEEPKCONFIGIDENTS__BA, $__r0
move.b $r0, [R_PORT_PB_DIR]
move.b KEEPKCONFIGIDENTS__BB, $__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 KEEPKCONFIGIDENTS__BE, $__r2
#endif
#ifdef CONFIG_ETRAX_PB_LEDS
move.b KEEPKCONFIGIDENTS__BG, $__r2
#endif
move.d (1 << KEEPKCONFIGIDENTS__BH) | (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
moveq KEEPKCONFIGIDENTS__CB, $__r6
;; If the first physical flash memory is exceeded wrap to the
;; second one
btstq 26, $r1 ; Are we addressing first flash?
bpl 1f
nop
clear.d $r6
1: test.d $r6 ; 0 = no wrapping
beq 2f
nop
lslq 20, $r6 ; Convert MB to bytes
sub.d $r1, $r6
2: addu.b [$r1+], $r0
subq 1, $r6 ; Flash memory left
beq 3f
subq 1, $r2 ; Length left
bne 2b
nop
ret
nop
3: move.d MEM_CSE1_START, $r1 ; wrap to second flash
ba 2b
nop
#endif
|