View Full Version: Bootloader firmware

camerahacks >>Camera Discussions >>Bootloader firmware


<< Prev | Next >>

morcheeba- 05-21-2005
Bootloader firmware
Has anyone tried reading the bootloader firmware yet? Since I've been away, BillW found some output registers. It would be pretty simple to write to $F71B as a bit-banged serial port and dump the entire memory contents while running in bootloader mode. There's a good chance that the boot ROM is still visible while this code runs, but not 100%. My previous attempt at this was done with a modification to the firmware - I modified it to read an arbitrary byte from memory and return it. I looped through all 64K and found that the unused ares ($4000-$EFFF) were just shadow images of RAM. The ROM must be bank-switched somehow, but since they only ever need to turn it off (and that code would be in the ROM itself), it would be hard to figure out how to turn the ROM on from normal FIRMWARE.BIN mode.

BillW- 05-21-2005

Cool idea - AFAIK it hasn't been done before! Is the plan to read the LED with a sensor or direct wire? Your plan reminded me a lot of the iPod firmware download hack, which sparked an idea. It might just be easier on the capture side to use speaker output instead. All that you need is a microphone and soundcard, or if you're ambitious an audio transformer connected to the speaker instead of the microphone.

morcheeba- 05-22-2005

Old rule of thumb: if it's less than 350 bytes, just assemble it by hand... ;) ok, I made that up. Connect a wire from the right side of the LED (D8, on the side towards the battery) to a standard 9-pin serial port, pin 2 (or pin 3 on a 25-pin port). Configure for 19200 buad, 8N1, and you're set! Be careful not to connect to the wrong pin - you might put -12v on the camera, which probably isn't too good. If output lines overlap, you may need to turn on CR->CR/LF translation, or save it to a text file and open with a text editor. The output is really pretty: ... 0090:E0 00 C8 1C F7 E0 00 C8 0098:1B F7 E6 00 E7 00 17 BF ... I wrote this code using only a multimeter and a stopwatch :) // Initialize the output port (I assume it's a direction register): 0xe0, 0x00, //0090: e0 32 +23 LDI R0,#$00 0xc8, 0x1c, 0xf7, //0092: c8 2bf7 +24 STA R0,$f72b ;($f71c) = $00 0xe0, 0x00, //0095: e0 01 +15 LDI R0,#$00 00=LED off, 0v at right side of LED, mark, data=1 0xc8, 0x1b, 0xf7, //0097: c8 02f7 +11 STA R0,$f71b // Initialize address counter (R7:R6) to 0000 0xe6, 0x00, //009a: e0 32 +23 LDI R6,#$00 0xe7, 0x00, //009c: e0 32 +23 LDI R7,#$00 // start of a line: 0x17, //009e: TX0 R7 0xbf, 0xcc, 0x01, //-- call hexout 0x16, //00a2: TX0 R6 //0xbc, 0xfb, 0, //jump to end-of-loop 0xbf, 0xcc, 0x01, //-- call hexout 0xe0, 0x3a, //00a6: e0 32 +23 LDI R0,#$3a (':') 0xbf, 0x03, 0x01, //-- call charout @ 0x0103 0xf6, //00ab: LDX R6 0xc6, //00ac: UPP R6 0xbf, 0xcc, 0x01, //-- call hexout 0xe0, 0x20, //00b0: e0 32 +23 LDI R0,#$20 (' ') 0xbf, 0x03, 0x01, //-- call charout @ 0x0103 0xf6, //00b5: LDX R6 0xc6, //00ac: UPP R6 0xbf, 0xcc, 0x01, //-- call hexout 0xe0, 0x20, //00b0: e0 32 +23 LDI R0,#$20 (' ') 0xbf, 0x03, 0x01, //-- call charout @ 0x0103 0xf6, //00bf: LDX R6 0xc6, //00ac: UPP R6 0xbf, 0xcc, 0x01, //-- call hexout 0xe0, 0x20, //00b0: e0 32 +23 LDI R0,#$20 (' ') 0xbf, 0x03, 0x01, //-- call charout @ 0x0103 0xf6, //00c9: LDX R6 0xc6, //00ac: UPP R6 0xbf, 0xcc, 0x01, //-- call hexout 0xe0, 0x20, //00b0: e0 32 +23 LDI R0,#$20 (' ') 0xbf, 0x03, 0x01, //-- call charout @ 0x0103 0xf6, //00d3: LDX R6 0xc6, //00ac: UPP R6 0xbf, 0xcc, 0x01, //-- call hexout 0xe0, 0x20, //00b0: e0 32 +23 LDI R0,#$20 (' ') 0xbf, 0x03, 0x01, //-- call charout @ 0x0103 0xf6, //00dd: LDX R6 0xc6, //00ac: UPP R6 0xbf, 0xcc, 0x01, //-- call hexout 0xe0, 0x20, //00b0: e0 32 +23 LDI R0,#$20 (' ') 0xbf, 0x03, 0x01, //-- call charout @ 0x0103 0xf6, //00e7: LDX R6 0xc6, //00ac: UPP R6 0xbf, 0xcc, 0x01, //-- call hexout 0xe0, 0x20, //00b0: e0 32 +23 LDI R0,#$20 (' ') 0xbf, 0x03, 0x01, //-- call charout @ 0x0103 0xf6, //00f1: LDX R6 0xc6, //00ac: UPP R6 0xbf, 0xcc, 0x01, //-- call hexout 0xe0, 0x0D, //00b0: e0 32 +23 LDI R0,#$0d ('\r') 0xbf, 0x03, 0x01, //-- call charout @ 0x0103 0xe0, 0x01, //00fb: LDI R0,#$01 value used to reset watchdog timer 0xc8, 0x16, 0xf7, //00fd: c8 02f7 +11 STA R0,$f716 - Reset watchdog timer 0xbc, 0x9e, 0x00, //0100: JMP L009e //------------------ #define DATA0 0xe2, 0x08, 0xca, 0x1b, 0xf7, // Uses R2 5 bytes #define DATA1 0xe2, 0x00, 0xca, 0x1b, 0xf7, // Uses R2 5 bytes #define BITDELAY 0xe2, 0x35, 0xe3, 0x01, 0x42, 0x99, 0xFD, 0x43, 0x99, 0xFA, // Uses R3,R2 10 bytes //------------------ // 0x0103: COUT routine (input: R0=character to output) DATA0 BITDELAY // 0x0103: start bit (15 bytes) // Send D0: (20 bytes) 0xe2, 0x08, // 0112: LDI R2,#$08 // assume DATA0 0x38, // 0114: ROR R0 0x91, 0x02, // BNC LABEL1 // we were correct 0xe2, 0x00, // LDI R2,#$08 // wrong - it was DATA1 0xca, 0x1b, 0xf7, // LABEL1: STA R2,$f71b BITDELAY // 10 bytes // Send D1: (20 bytes) 0xe2, 0x08, // 0126: LDI R2,#$08 // assume DATA0 0x38, // ROR R0 0x91, 0x02, // BNC LABEL1 // we were correct 0xe2, 0x00, // LDI R2,#$08 // wrong - it was DATA1 0xca, 0x1b, 0xf7, // LABEL1: STA R2,$f71b BITDELAY // Send D2: (20 bytes) 0xe2, 0x08, // 013a: LDI R2,#$08 // assume DATA0 0x38, // ROR R0 0x91, 0x02, // BNC LABEL1 // we were correct 0xe2, 0x00, // LDI R2,#$08 // wrong - it was DATA1 0xca, 0x1b, 0xf7, // LABEL1: STA R2,$f71b BITDELAY // Send D3: (20 bytes) 0xe2, 0x08, // LDI R2,#$08 // assume DATA0 0x38, // ROR R0 0x91, 0x02, // BNC LABEL1 // we were correct 0xe2, 0x00, // LDI R2,#$08 // wrong - it was DATA1 0xca, 0x1b, 0xf7, // LABEL1: STA R2,$f71b BITDELAY // Send D4: (20 bytes) 0xe2, 0x08, // 0162: LDI R2,#$08 // assume DATA0 0x38, // ROR R0 0x91, 0x02, // BNC LABEL1 // we were correct 0xe2, 0x00, // LDI R2,#$08 // wrong - it was DATA1 0xca, 0x1b, 0xf7, // LABEL1: STA R2,$f71b BITDELAY // Send D5: (20 bytes) 0xe2, 0x08, // LDI R2,#$08 // assume DATA0 0x38, // ROR R0 0x91, 0x02, // BNC LABEL1 // we were correct 0xe2, 0x00, // LDI R2,#$08 // wrong - it was DATA1 0xca, 0x1b, 0xf7, // LABEL1: STA R2,$f71b BITDELAY // Send D6: (20 bytes) 0xe2, 0x08, // 018a: LDI R2,#$08 // assume DATA0 0x38, // ROR R0 0x91, 0x02, // BNC LABEL1 // we were correct 0xe2, 0x00, // LDI R2,#$08 // wrong - it was DATA1 0xca, 0x1b, 0xf7, // LABEL1: STA R2,$f71b BITDELAY // Send D7: (20 bytes) 0xe2, 0x08, // 019e: LDI R2,#$08 // assume DATA0 0x38, // ROR R0 0x91, 0x02, // BNC LABEL1 // we were correct 0xe2, 0x00, // LDI R2,#$08 // wrong - it was DATA1 0xca, 0x1b, 0xf7, // LABEL1: STA R2,$f71b BITDELAY DATA1 BITDELAY // 01b2: stop bit (15 bytes) BITDELAY // 01c1: stop bit (10 bytes) 0xb9, // 01cb: RTS //------------------ // 0x01cc: HEXOUT routine (input: R0=byte to output) 0x71, // 01cc: T0X R1 save it.. 0x38, // 01cd: ROR R0 0x38, // ROR R0 shift high nibble into lower 0x38, // ROR R0 0x38, // 01d0: ROR R0 0xe2, 0x0F, // 01d1: LDI R2,#$0F 0x22, // 01d3: AND R2 0xbf, 0xdb, 0x01, // 01d4: call xdigitout @ 0x0103 0x11, // 01d7: TX0 R1 get saved byte 0xe2, 0x0F, // 01d8: LDI R2,#$0F 0x22, // 01da: AND R2 // fall into xdigitoout & return //------------------ // 0x01db: XDIGITOUT (input: R0=nibble to output) 0xe2, 0x30, // 01d8: LDI R2,#$30 - make a digit 0x52, // 01da: ADD R2 0xe2, 0x3A, // 01d8: LDI R2,#$3A 0x7a, // 01da: CMP R2 0x91, 0x03, // 01db: BNC ISDIGIT 0xe2, 0x07, // 01dd: LDI R2,#$07 - make a letter ('A'-'0' - 10) 0x52, // 01df: ADD R2 0xbc, 0x03, 0x01, // 01e0: ISDIGIT: jump to charout @ 0x0103

morcheeba- 05-22-2005

bah. I looked at the data and it looked like the first 0x4000 bytes of the firmware file. 0x4000-0xE000 were the repeated images of 0-3fff. I should try this program on the camera I have with the flash chip removed. So, some questions... - Is the processor executing out of an instruction-access, not data access area? - Did the bootloader firmware flip a bit to disable rom access before running my little program? - Maybe I am seeing the bootloader... but it shouldn't have things in it like "SPLASH.TFT" because it doesn't need to access the LCD. - Why did I see memory from 1000-3FFF of FIRMWARE.BIN. I would have thought it would be have left the end of the firmware in memory (where my bad checksum resides) Also, from this adventure, I found about a possible data-direction-register (f71c) and the shutter close bit in f71b - documented here.

mconsidine- 05-22-2005

The first 40 bytes at the two locations you suggest (0 and x4000) of the 16M file I pulled down start out as you suggest. Then for the next 270 or so bytes they are somewhat different. After that, they bear no resemblence to each other. Can you suggest how I should look at this file? The file obviously has structure, as well as identifiable text (e.g. MENU.TFT, RAWJPG, etc. ) (6520/28 Blue)

morcheeba- 05-22-2005

Good catch! I think you're right - I was too quick to judge. bootrom.txt 00003860 90 f5 8c b9 52 41 57 00 4d 45 4e 55 2e 54 46 54 |....RAW.MENU.TFT| 00003870 00 53 48 55 54 44 4f 57 4e 2e 54 46 54 00 53 50 |.SHUTDOWN.TFT.SP| firmware6410.txt has similar code, but at a different address 000037d0 90 f5 8c b9 52 41 57 00 4d 45 4e 55 2e 54 46 54 |....RAW.MENU.TFT| 000037e0 00 53 48 55 54 44 4f 57 4e 2e 54 46 54 00 53 50 |.SHUTDOWN.TFT.SP| ... might be some good stuff in there after all! I did re-verify the repeating memory map... [Morcheebas-Computer:SMaL Camera docs/reader/bootrom] % grep RAW BOOTROM.TXT 00003860 90 f5 8c b9 52 41 57 00 4d 45 4e 55 2e 54 46 54 |....RAW.MENU.TFT| 00003940 38 21 38 17 38 0d 38 03 38 f9 37 49 38 52 41 57 |8!8.8.8.8.7I8RAW| 00007860 90 f5 8c b9 52 41 57 00 4d 45 4e 55 2e 54 46 54 |....RAW.MENU.TFT| 00007940 38 21 38 17 38 0d 38 03 38 f9 37 49 38 52 41 57 |8!8.8.8.8.7I8RAW| 0000b860 90 f5 8c b9 52 41 57 00 4d 45 4e 55 2e 54 46 54 |....RAW.MENU.TFT| 0000b940 38 21 38 17 38 0d 38 03 38 f9 37 49 38 52 41 57 |8!8.8.8.8.7I8RAW| 16MB? - the file should only be 64k * 3.6bytes/char = approx, 230KB (that's some fast work!)

BillW- 05-23-2005

Nicely done, and points for style on the program output! Next time try to get some hardware flow control in there, will ya? :wink: BTW, does your flash-removed camera do 4 bootloader beeps, or? If the TFTs you saw referenced in code were just shutdown, splash, and menu, it may not be that unusual. These are TFTs used in non-pv2 cameras. Doubtlessly SMaL has just linked the bootloader against some standard filesystem access library they use, and it has those constants in it. (It's a theory anyway)

zapped- 07-13-2005

Could you post the ready to assemble code? <edit> never mind, after three years I think I figured it out. ; bbSerial dumps Ram to bit-banged serial using LED on camera ;Connect a wire from the right side of the LED (D8, on the side towards the battery) to a standard 9-pin serial port, pin 2 (or pin 3 on a 25-pin port). Configure for 19200 buad, 8N1, and you're set! Be careful not to connect to the wrong pin - you might put -12v on the camera, which probably isn't too good. ;If output lines overlap, you may need to turn on CR->CR/LF translation, or save it to a text file and open with a text editor. ;The output is really pretty: ;... ;0090:E0 00 C8 1C F7 E0 00 C8 ;0098:1B F7 E6 00 E7 00 17 BF ;... ;**{--------------------------------------------- B3A916B8.00090 ---- ;** ;entry point ;**}----------------------------------------------------------------- .ORG $90 L0090: LDI R0,#$00 ;Initialize the output port STA R0,$f71c LDI R0,#$00 STA R0,$f71b ;00=LED off, 0v at right side of LED, mark, data=1 LDI R6,#$00 LDI R7,#$00 ;Initialize address counter (R7:R6) to $0000 LOOPTOP: TX0 R7 JSR HEXOUT TX0 R6 JSR HEXOUT LDI R0,#$3a ;(':') JSR COUT LDX R6 UPP R6 JSR HEXOUT LDI R0,#$20 ;(' ') JSR COUT LDX R6 UPP R6 JSR HEXOUT LDI R0,#$20 ;(' ') JSR COUT LDX R6 UPP R6 JSR HEXOUT LDI R0,#$20 ;(' ') JSR COUT LDX R6 UPP R6 JSR HEXOUT LDI R0,#$20 ;(' ') JSR COUT LDX R6 UPP R6 JSR HEXOUT LDI R0,#$20 ;(' ') JSR COUT LDX R6 UPP R6 JSR HEXOUT LDI R0,#$20 ;(' ') JSR COUT LDX R6 UPP R6 JSR HEXOUT LDI R0,#$20 ;(' ') JSR COUT LDX R6 UPP R6 JSR HEXOUT LDI R0,#$0d ;(carriage return) JSR COUT LDI R0,#$01 STA R0,$f716 ;Reset watchdog timer JMP LOOPTOP ;**{--------------------------------------------- B4F1551A.00103 ---- ;** ;character output on LED as bit banged serial port ;**}----------------------------------------------------------------- COUT: LDI R2,#$08 ;DATA0 STA R2,$f71b ;($f71b) = $08 LDI R2,#$35 ;BITDELAY LDI R3,#$01 ;R3:R2 = $0135 L010C: DEC R2 BRC L010C DEC R3 BRC L010C ;Send Bit D0: LDI R2,#$08 ;assume DATA0 ROR R0 BNC L0119 ;branch if we were correct LDI R2,#$00 ;else it was DATA1 L0119: STA R2,$f71b ;($f71b) = $00 LDI R2,#$35 ;BITDELAY LDI R3,#$01 ;R3:R2 = $0135 L0120: DEC R2 BRC L0120 DEC R3 BRC L0120 ;Send Bit D1: LDI R2,#$08 ;assume DATA0 ROR R0 BNC L012D ;branch if we were correct LDI R2,#$00 ;else it was DATA1 L012D: STA R2,$f71b ;($f71b) = $00 LDI R2,#$35 ;BITDELAY LDI R3,#$01 ;R3:R2 = $0135 L0134: DEC R2 BRC L0134 DEC R3 BRC L0134 ;Send Bit D2: LDI R2,#$08 ;assume DATA0 ROR R0 BNC L0141 ;branch if we were correct LDI R2,#$00 ;else it was DATA1 L0141: STA R2,$f71b ;($f71b) = $00 LDI R2,#$35 ;BITDELAY LDI R3,#$01 ;R3:R2 = $0135 L0148: DEC R2 BRC L0148 DEC R3 BRC L0148 ;Send Bit D3: LDI R2,#$08 ;assume DATA0 ROR R0 BNC L0155 ;branch if we were correct LDI R2,#$00 ;else it was DATA1 L0155: STA R2,$f71b ;($f71b) = $00 LDI R2,#$35 ;BITDELAY LDI R3,#$01 ;R3:R2 = $0135 L015C: DEC R2 BRC L015C DEC R3 BRC L015C ;Send Bit D4: LDI R2,#$08 ;assume DATA0 ROR R0 BNC L0169 ;branch if we were correct LDI R2,#$00 ;else it was DATA1 L0169: STA R2,$f71b ;($f71b) = $00 LDI R2,#$35 ;BITDELAY LDI R3,#$01 ;R3:R2 = $0135 L0170: DEC R2 BRC L0170 DEC R3 BRC L0170 ;Send Bit D5: LDI R2,#$08 ;assume DATA0 ROR R0 BNC L017D ;branch if we were correct LDI R2,#$00 ;else it was DATA1 L017D: STA R2,$f71b ;($f71b) = $00 LDI R2,#$35 ;BITDELAY LDI R3,#$01 ;R3:R2 = $0135 L0184: DEC R2 BRC L0184 DEC R3 BRC L0184 ;Send Bit D6: LDI R2,#$08 ;assume DATA0 ROR R0 BNC L0191 ;branch if we were correct LDI R2,#$00 ;else it was DATA1 L0191: STA R2,$f71b ;($f71b) = $00 LDI R2,#$35 ;BITDELAY LDI R3,#$01 ;R3:R2 = $0135 L0198: DEC R2 BRC L0198 DEC R3 BRC L0198 ;Send Bit D7: LDI R2,#$08 ;assume DATA0 ROR R0 BNC L01A5 ;branch if we were correct LDI R2,#$00 ;else it was DATA1 L01A5: STA R2,$f71b ;($f71b) = $00 LDI R2,#$35 ;BITDELAY LDI R3,#$01 ;R3:R2 = $0135 L01AC: DEC R2 BRC L01AC DEC R3 BRC L01AC ;Send Stop Bit LDI R2,#$00 ;DATA1 STA R2,$f71b ;($f71b) = $00 LDI R2,#$35 ;BITDELAY LDI R3,#$01 ;R3:R2 = $0135 L01BB: DEC R2 BRC L01BB DEC R3 BRC L01BB LDI R2,#$35 ;BITDELAY LDI R3,#$01 ;R3:R2 = $0135 L01C5: DEC R2 BRC L01C5 DEC R3 BRC L01C5 RTS ;**{--------------------------------------------- 4C3EE027.001CC ---- ;** ;hexout routine (input: R0=byte to output) ;**}----------------------------------------------------------------- HEXOUT: T0X R1 ;save it.. ROR R0 ROR R0 ROR R0 ;shift high nibble into lower ROR R0 LDI R2,#$0f AND R2 JSR XDIGITOUT TX0 R1 LDI R2,#$0f AND R2 ;fall into xdigitout & return XDIGITOUT: ;(input: R0=nibble to output) LDI R2,#$30 ;- make a digit ADD R2 ;R0 += $30 LDI R2,#$3a CMP R2 BNC L01E6 LDI R2,#$07 ;- make a letter ('A'-'0' - 10) ADD R2 ;R0 += $07 L01E6: JMP COUT

zapped- 07-14-2005

took me three years, but I think I figured it out

radarman- 07-14-2005

I've got a few questions about the bootloader, but I'm too busy tracing through the firmware file to mess with extracting it. 1) When the bootloader transfers control to the firmware, where does it start? 0x90 or main() (exact position differs between FW revisions) 2) Can you have a firmware .bin that is shorter and/or longer than the current firmware file? I suppose if it is shorter, you could pad it - longer? Perhaps an additional file? I'd be curious to see if you could write your own wee firmware.bin with a simple program (perhaps to blink the ready light or something) and have the bootloader start it, rather than give the two beeps. I'm hoping there is something in the firmware.bin that tells the bootloader where to look for the checksum, and that it doesn't simply depend on the size of the file (though it looks iffy, given that 4 different revisions all have identically sized firmware.bin files)

brite_eye- 07-14-2005

BillW supplied a few examples of very small .pv2 routines that just beep and twill speaker. Download his devkit from source forge and try those. https://sourceforge.net/project/showfiles.php?group_id=134210&package_id=147378&release_id=316223

BillW- 07-14-2005

When the bootloader transfers control to the firmware, where does it start? 0x90 or main() (exact position differs between FW revisions) I believe it's 0x90, and I think morcheeba did too. FWIW, the $26 and $28 USB commands also jump to that location when they execute user programs. Can you have a firmware .bin that is shorter and/or longer than the current firmware file? Some of the drivers for the cameras come with .pak files that appear to have firmware like code, including checksums IIRC, and they were various sizes. I'd be curious to see if you could write your own wee firmware.bin with a simple program You could, but the size mechanism (if it exists) is unknown. You might try just creating a small firmware with the checksum in the same place relative to the end. If that doesn't work, it's just as easy to pad to the correct size and let pv2tool take care of the checksum. Note that you'll need to short flash to recover from such a featureless firmware.

radarman- 08-16-2005

Based on my experience - and what I read here - I don't think we are going to be extracting the boot ROM ourselves. It is very easy for the ROM to simply turn itself off as it tranfers control to a user program - to avoid what we are trying to do. For those wondering, in an ASIC or FPGA - it really isn't hard to simply delay an action for a few clocks. That also explains why you can simply do an RTS, and return directly to the bootloader. Once your program runs, it essentially has the run of the memory space. When it quits, or runs amok, the camera just resets when the watchdog timer expires. In a way, this is good - because it means you don't have to make your -*test*-('") firmware step out of the way of the boot ROM. That's why I suspect that as soon as you execute a program using the bootloader, it silently turns itself off. There is no need to reenable either - you just let the camera reboot on its own.

zapped- 02-26-2008

Given that the registers for specifying memory addresses start at $fx00, possibly the camera uses $f400 or $f600 for as the on-ASIC FLASH or ROM where the bootloader resides. If there exists a flash-able area on the ASIC then the bootloader may not be quite as good protection against bricking as currently believed. On another note, is anyone up to writing a program to do bit-banged serial transfer TO the pv2?

Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.