summaryrefslogtreecommitdiffstats
path: root/oncology/dpfhack_display/reverse
diff options
context:
space:
mode:
authorroot <root@filebitch>2011-08-28 18:28:51 +0200
committerroot <root@filebitch>2011-08-28 18:28:51 +0200
commitc8c27e3af96a84ccf8ecdfd7610e49dba0598e7d (patch)
tree3cb1a59b301f91b6a1524b48fb9d828a78a43dac /oncology/dpfhack_display/reverse
parent99bdbc04f2be1f0d27c4a4dde692e8a5b6eb8a7e (diff)
parent7a97f9d4baff89bbcfa4bef93ab4d4246b2b82e6 (diff)
Merge branch 'master' of https://github.com/krebscode/painload
Diffstat (limited to 'oncology/dpfhack_display/reverse')
-rw-r--r--oncology/dpfhack_display/reverse/Makefile76
-rw-r--r--oncology/dpfhack_display/reverse/README169
-rw-r--r--oncology/dpfhack_display/reverse/common.in213
-rw-r--r--oncology/dpfhack_display/reverse/dump.py470
4 files changed, 928 insertions, 0 deletions
diff --git a/oncology/dpfhack_display/reverse/Makefile b/oncology/dpfhack_display/reverse/Makefile
new file mode 100644
index 00000000..d0a28b68
--- /dev/null
+++ b/oncology/dpfhack_display/reverse/Makefile
@@ -0,0 +1,76 @@
+# Makefile for DPF firmware analysis
+
+
+CFLAGS = -g
+
+ASFLAGS = -plosgff
+
+ifndef DUMP
+ DUMP = -d
+endif
+
+VERSION = 0.01develop
+
+AS = asx8051
+
+INFILES = $(wildcard code*.in) $(wildcard dump*.in) $(wildcard data*.in)
+
+ASMFILES = $(INFILES:%.in=%.asm)
+BINFILES = $(INFILES:%.in=%.bin)
+
+all: $(ASMFILES)
+
+show:
+ echo $(ASMFILES)
+
+all.asm: $(ASMFILES)
+ @echo concatenating all ASM files into $@
+ @cat $(ASMFILES) > $@
+
+%.rel : %.asm
+ $(AS) $(ASFLAGS) $<
+
+# Fixup format:
+%.asm: %.d52
+ @echo Generating $@
+ @sed 's/\.equ/=/g;s/^\s*end/; END/g' $< > $@
+
+test: main.o
+ $(CC) -o $@ $<
+
+clean: cleanimages
+ rm -f test *.ctl *.asm dump*.bin code*.bin *.d52 *.lst *.rel *.sym
+
+common.in:
+ ln -s ../common.in .
+
+dump%.ctl: dump%.in common.in
+ @cat $< common.in >$@
+
+code_%.ctl: code_%.in common.in
+ @cat $< common.in >$@
+
+data_%.ctl: data_%.in
+ @cp $< $@
+
+%.d52: %.bin %.ctl
+ @d52 -p -b $(DUMP) -n $< # >/dev/null
+
+cleanimages:
+ rm -fr images/*
+
+RAWFILES = $(wildcard *.raw)
+
+IMAGES = $(RAWFILES:%.raw=images/%.png)
+
+images/%.png: %.raw
+ convert -size 128x128 -depth 1 gray:$< $@
+
+images: $(IMAGES)
+
+dump:
+ PWD=`pwd`; BASE=`basename $$PWD`; \
+ echo $$BASE; \
+ python ../dump.py $$BASE full_image.bin
+
+.PHONY: dump
diff --git a/oncology/dpfhack_display/reverse/README b/oncology/dpfhack_display/reverse/README
new file mode 100644
index 00000000..c70fa49e
--- /dev/null
+++ b/oncology/dpfhack_display/reverse/README
@@ -0,0 +1,169 @@
+Reverse engineering HOWTO
+----------------------------------------------------------------------------
+
+Here it is, the long awaited hacking howto for the AX206 DPFs.
+
+BIG FAT WARNING: You have to be able to read 8051 assembly code and you
+HAVE TO know what it is doing. Otherwise you will likely brick your frame
+and we will all laugh at you.
+
+Also you should know something about the SPI flash layout, have a look
+at the m25p80 datasheets found all over the web. Basically you should
+remember that the flashes are organized in sectors of 0x10000 size.
+
+Since the boot loader mode is a big secret, we have to exploit the hardware
+somewhat to get into the "Developer Mode" (hacking is a ugly word).
+To implement developer mode, we normally use the strategy to modify the
+powerdown routine such that when USB is plugged in and you press and hold
+MENU for a few seconds, it will enter the modified state.
+This allows us to return to the original firmware by pressing RESET.
+
+To get started, you need a few tools and items:
+- A dump of your DPFs firmware (look for fulldump.py script from the
+ dpfhack-*.tgz archive to create one)
+- The d52 disassembler: http://www.8052.com/users/disasm/
+- Installed Python package
+
+The dump binary first needs to be split up into single modules.
+Why modules? The memory of the AX206 isn't big enough to store a full
+program, thus a bank switching technique is used. A bank switched call
+looks like:
+
+ mov a,#0x1e ; 13a2 74 1e t.
+ mov dptr,#mod31_1330; 13a4 90 13 30 ..0
+ lcall tramp_jsr ; 13a7 12 19 38 ..8
+
+The number moved into 'a' is the module number minus one. The dump.py
+script analyses the code, so you will only have to look at the modXX_XXXX
+function. This is the target function called in the according module.
+The loading on demand and calling of the function is handled by
+tramp_jsr().
+
+
+1. First, you copy the generated dump (full.bin) into a folder, like
+ dpf/reverse/new and rename it to full_dump.bin
+2. Run the makefile:
+ > make -f ../Makefile dump"
+ You will end up with a number of
+ *.in files in the current directory if this was successful.
+3. Run make again:
+ > make -f ../Makefile
+ Now you should have a few *.asm files in the working directory.
+4. Identify the powerdown module. Normally, it helps to grep for p2up:
+ > grep p2up *.asm
+ That should list a module with number around 36 or 37.
+5. The powerdown ROUTINE is the function that is called most often from many
+ modules, but most probably NOT called from module 1 (dump01). In many
+ cases, this turned out to be mod37_1330.
+
+WARNING: You have to make sure that this module does not live in sector
+0x000000 of the flash (see "dump file offset" tag in the header of the
+assembly file). If it lives in sector 0x000000, the described method
+will NOT work and you will brick your DPF.
+
+5. Find the splash screen routine that is called from the powerdown.
+ This is normally the routine called at the beginning of the powerdown
+ routine and contains code like:
+
+ mov G_lcd_cxH,a ; 1509 f5 78 ux
+ mov G_lcd_cyL,a ; 150b f5 79 uy
+ mov G_lcd_cyH,a ; 150d f5 7a uz
+ mov G_lcd_dxL,a ; 150f f5 7b u{
+
+6. This routine you can patch. Take a p_start_*.s from an already hacked frame
+ and make sure you understand what is happening. Adapt the .org statements
+ to the locations where YOUR patched code can safely live.
+
+7. The final jump into the patched firmware occurs at the bottom of the
+ patch, looking like
+
+ mov a,#(53 - 1)
+ mov dptr,#entry_addr
+ ljmp tramp_jmp
+
+ The module number in here will be the number of the last module you
+ extracted, PLUS ONE - because we are gonna add an extra module.
+ For this, the jump table will need to be modified.
+
+8. We do not touch the original jump table, but make a copy of it (because
+ it lives in sector 0x000000). The jump table record for this extra module
+ will be stored in the end table tag which can be read clear text in the
+ dump00.asm as "-EndTbl-". Have a look at a jmptbl_*.s file, the .org
+ statement - i.e. the address offset - has to be the offset address of the
+ "-EndTbl-" string.
+
+9. Have a look at the hackit.py script. The critical function overwriting
+ data on the flash is the .patchSector() method, called like
+
+ d.patchSector(start, flashaddr, hexfile)
+
+ start is the relocation start address of the hexfile that the flash is
+ patched with, it is normally identical with the first .org offset specified
+ in the *.s file.
+ flashaddr is where it is stored on the flash.
+ hexfile is the intel hex data file the flash is patched with.
+
+ The hackit.py framework will take care of the patching, so you merely
+ will need to add another configuration record in profiles.py.
+
+ This is an example record:
+
+patch_pink = [
+ (COPY, [0x000000, 0x3f0000]), # Copy sector 0
+ (PATCH, [0x0, 0x3f0000], "jmptbl_pink.ihx"),
+ (BINARY, [0x0, 0x390000], "font4x8.bin"),
+ (PATCH, [0x0, 0x380000], "fw_pink.ihx"),
+ (37, [ 0x87f37fa6, 0xc8c55832, 0x27b13328 ] , "p_start_pink.ihx"),
+]
+
+ The first COPY statement tells hackit to make a copy of the first sector
+ to the specified address, which should be at the end of the flash.
+ The PATCH statements patch the given sector address with the hex file
+ specified.
+ The BINARY option just copies a plain binary to the given address.
+ Finally, the very critical patching of the powerdown routine.
+ The first number (here 37) is the module number of the powerdown routine
+ as identified by you. Then, a list of known CRC32 checksums follow.
+ If the sector to be patched here is unknown by its CRC32, it will refuse
+ to patch it and print out the non matching CRC32.
+
+ When you are ABSOLUTELY sure your hack will not overwrite anything crucial,
+ you can insert this CRC32 as first number in the list.
+
+10. Did you do the paranoia check of all addresses and offsets, do you
+ understand where things will go? If in doubt, make a dry run with the
+ patchSector function on an empty/unused sector, preferrably at the
+ end of your flash. Then analyze the dump again.
+
+Finally, you can try hacking your DPF with the hackit.py.
+Once it is hacked, it will again print out a non matching CRC32 if you
+run the hackit.py again. This CRC32 you insert as LAST number (mycrc)
+in the list:
+
+ (37, [ original_crc, my_crc ] , "p_start_mine.ihx"),
+
+Now you can test your hack and publish the profiles.py on success.
+
+----------------------------------------------------------------------------
+
+A few advices:
+
+REMEMBER: Never touch sector zero (address 0x000000 - 0x010000). Never ever.
+
+If you bricked your frame, don't throw it away YET. Maybe some day
+we'll discover how the bootloader works. And you could still use the
+display for tinkering. If you have any knowledge of the boot loader,
+speak up!
+
+Don't ask us to help you with the hacking. Try it yourself or use one of
+the DPFs that are known to work.
+It can take a few months to learn 8051 assembly from scratch,
+but don't give up, it will be a great learning experience and later
+help you to get a good job :-)
+
+Just read the source, duke.
+
+----------------------------------------------------------------------------
+Brought to you by:
+
+- hackfin, the evil fish, and others
diff --git a/oncology/dpfhack_display/reverse/common.in b/oncology/dpfhack_display/reverse/common.in
new file mode 100644
index 00000000..8b64196c
--- /dev/null
+++ b/oncology/dpfhack_display/reverse/common.in
@@ -0,0 +1,213 @@
+; ---- END USER DEFINED ----
+; Common stuff: seems mostly common to all firmware. No guarantee
+; about correctness of the global variables for all firmwares.
+; Routines in ROM:
+
+l 001e rom_001e
+
+; might not exist:
+l 0911 rom_0911
+
+; Likely some JPEG decoding
+l 0a27 rom_0a27
+l 0a85 rom_0a85
+l 0add rom_0add
+l 0d38 rom_0d38
+l 0d65 rom_0d65
+l 0e02 rom_0e02
+l 0f5c rom_0f5c
+l 0fa9 rom_0fa9
+
+l 0c0a rom_bootload
+
+; Called from IRQ routines:
+l 0e1a rom_0e1a
+l 0e72 rom_0e72
+l 0ef4 rom_0ef4
+l 0f16 rom_0f16
+
+; Writes a byte to the LCD port p3
+l 0f25 rom_lcdwrite
+; Probably alternative write function
+l 0f34 rom_0f34
+
+; Called from bank switching code:
+l 0fae rom_0fae
+
+s 0e00 common_xdata_0e00
+s 0e40 common_xdata_0e40
+s 0e80 common_xdata_0e80
+s 1600 common_xdata_0e00_cseg
+; s 1640 common_xdata_0e40_cseg
+; s 1680 common_xdata_0e80_cseg
+
+; Common functions that seem to be called from all modules:
+
+l 124a g_var0
+l 1280 lcd_setcontext
+
+; Those might differ between different DPF firmware
+s 1800 common_usb_1800
+s 1818 common_usb_resume_1818
+
+; Most important: module loader trampoline
+l 1934 tramp_return
+l 1938 tramp_jsr
+l 193a tramp_jmp
+l 193e tramp_dyn
+
+; Global register variables(flags):
+; _oi: Probably initialized in OTP
+; G_: Very likely global over all modules (not overlayed)
+; g_: Global (shared) among some modules, may be overlayed
+; i_: Accessed from IRQ handler
+r 0f G_ptr0_oi
+r 10 G_count0
+r 11 G_adcbufadr
+r 12 G_count1
+r 13 G_curp_l
+r 14 G_curp_h
+r 19 G_seconds?
+r 1b G_internal
+r 1d G_var
+r 1e G_button
+r 1f G_bankno
+r 20 i_G_f
+r 21 G_adc_flags
+r 22 G_irqh6_flags
+r 25 G_usbflg
+r 26 g_sector_h
+r 27 g_sector_m
+r 28 g_sector_l
+r 29 flags_29
+r 2a flags_2a
+r 2b flags_2b
+r 2c flags_2c
+r 2d flags_2d
+r 2e flags_2e
+r 2f flags_2f
+r 73 G_language
+; The following registers denote the LCD controller context area
+; See lcd_setcontext()
+r 77 G_lcd_cxL
+r 78 G_lcd_cxH
+r 79 G_lcd_cyL
+r 7a G_lcd_cyH
+r 7b G_lcd_dxL
+r 7c G_lcd_dxH
+r 7d G_lcd_dyL
+r 7e G_lcd_dyH
+
+; AX206 SFRs
+
+f 86 dpcon
+f 87 pcon
+
+f 91 _mulres0
+f 92 _mulres1
+f 93 _mulres2
+f 94 _mulres3
+f 9a _wkpnd
+f 9b _wken
+f 9c _wkedg
+f a4 _pie
+f a5 _ckcon
+f a8 _ien0
+f b0 _p3
+f b1 _tmr0con
+f b3 _tmr0cnt
+f b4 _tmr0pr
+f b5 _tmr0psr
+f b8 _ip
+f bb _wdtcon
+f c0 _p4
+f c1 _tmr2con
+f c2 _tmr2cntl
+f c3 _tmr2cnth
+f c4 _tmr2perl
+f c5 _tmr2perh
+f c6 _tmr2pwml
+f c7 _tmr2pwmh
+f c8 _usbcon0
+f c9 _usbdata
+f ca _usbaddr
+f d1 _rtcnt
+f d2 _adccon
+f d3 _adcbaud
+f d4 _adcbufh
+f d6 _spibaud
+f d7 _spibuf
+f d8 _spicon
+f dc _adcbufl
+f e1 _tmr1con
+f e2 _tmr1cntl
+f e3 _tmr1cnth
+f e4 _tmr1perl
+f e5 _tmr1perh
+f e6 _tmr1pwml
+f e7 _tmr1pwmh
+f e8 _eif0
+f e9 _p0dir
+f ea _p1dir
+f eb _p2dir
+f ec _p3dir
+f ed _p4dir
+f f1 _uartsta
+f f2 _uartcon
+f f3 _uartbaud
+f f4 _uartbuf
+f f8 _tmr3con
+f f9 _p0up
+f fa _p1up
+f fb _p2up
+f fc _p3up
+f fd _p4up
+
+; Addressable bits:
+m 00 i_G_f.0
+m 01 i_G_f.1
+m 02 i_G_f.adcready
+m 03 i_G_f.usbon
+m 04 i_G_f.usbact
+m 05 i_G_f.wkup
+m 06 i_G_f.6
+m 07 i_G_f.7
+m 0f G_rtc2_flags.7
+m 10 sflags.0
+m 11 i_G_flag.1
+m 12 g_sflags.2
+m 13 sflags.3
+m 14 sflags.4
+m 15 sflags.5
+m 16 sflags.6
+m 17 sflags.7
+m 18 G_flags23.0
+m 19 G_flags23.1
+m 1a G_flags23.2
+m 20 bit_24.0
+m 21 bit_24.1
+m 22 bit_24.2
+m 23 bit_24.3
+m 24 bit_24.4
+m 25 bit_24.5
+m 26 bit_24.6
+m 27 bit_24.7
+m 28 G_usbflg.0
+m 29 G_usbflg.1
+m 2a G_usbflg.2
+m 2b G_usbflg.3
+m 2c G_usbflg.4
+m 2d G_usbflg.5
+
+; I/O mappings:
+k 86 _BUT_MENU
+k 90 _LCD_RST
+k 91 _LCD_WR
+k 92 _LCD_RD
+k 94 _LCD_A0
+k a0 _SPI_CS
+k a1 _LCD_CS
+k ce _USB_DONE
+k df _SPIPND
+k fb _T3CP
+k e8 _T0P
diff --git a/oncology/dpfhack_display/reverse/dump.py b/oncology/dpfhack_display/reverse/dump.py
new file mode 100644
index 00000000..cbbc563b
--- /dev/null
+++ b/oncology/dpfhack_display/reverse/dump.py
@@ -0,0 +1,470 @@
+# DPF dump splitter
+# <hackfin@section5.ch>
+#
+# Takes a binary dump of the DPF and splits it into the banked modules
+# Usage:
+# 1. First, simply run this script after having dumped your entire DPF
+# into full_image.bin. It will generate a lot of dump* files.
+# 2. Then analyze the addresses in dump00.asm. The code is loading more
+# common code segments from other addresses. To extract this code,
+# enhance or create a record in g_dpfs. Later on, we'll add some
+# firmware version detection...
+#
+
+import os
+import sys
+import struct
+# import scantool
+
+IMGLEN1 = 128 * 128 / 8
+IMGLEN16 = 128 * 128 * 2
+
+# menu table in code memory:
+table_addr = 0x1600
+
+g_dpfs = {
+ 'default' : [
+ [], [], [], [],
+ ],
+ 'silver2' : [
+ [
+ (0x2f0, 0x1934, 0x19f2),
+ (0x3ae, 0x1003, 0x1270),
+ (0x6a0, 0x1280, 0x12bc),
+ ],
+ [],
+ [],
+ [],
+ ],
+ 'black' : [
+ [
+ (0x2e0, 0x1934, 0x19f2),
+ (0x39e, 0x1003, 0x1270),
+ (0x682, 0x1280, 0x12d0),
+ ],
+ [],
+ [],
+ [],
+ ],
+ 'white' : [
+ [
+ (0x2f0, 0x1934, 0x19f2),
+ (0x3ae, 0x1003, 0x1270),
+ (0x69c, 0x1280, 0x12d0),
+ (0x2fec, 0x1800, 0x189d),
+ ],
+ [],
+ [],
+ [],
+ ],
+ 'visualland' : [
+ [
+ (0x2c0, 0x1934, 0x19f2),
+ (0x37e, 0x1003, 0x1270),
+ (0x662, 0x1280, 0x12d0),
+ ],
+ [],
+ [],
+ [],
+ ],
+ 'blue' : [
+ [ # special code segments: fileoffset, start, end
+ (0x2c0, 0x1934, 0x19f2),
+ (0x37e, 0x1003, 0x1270),
+ (0x662, 0x1280, 0x12d8),
+ (0x3474, 0x1800, 0x189d),
+
+ # Dynamic jump table:
+ (0x0e54, 0xce7 + 0x800, 0xce7 + 0x800 + 0x2c2),
+ ],
+ [ # images: name, fileoffset, rel_start, rel_end
+ ("img0", 0x55bbb, 0x0, IMGLEN16),
+ ("img1", 0x4eb89, 0x0, IMGLEN1),
+ ("usb_conn", 0x4ec89, 0x0, 0x80 * 0x48),
+ ("menu0", 0x4e289, 0x0, IMGLEN1),
+ ("menu1", 0x4e389, 0x0, IMGLEN1),
+ ("menu2", 0x4ee89, 0x0, IMGLEN1),
+ ("menu3", 0x4e489, 0x0, IMGLEN1),
+ ("menu4", 0x4e589, 0x0, IMGLEN1),
+ ("menu5", 0x4e789, 0x0, IMGLEN1),
+ ("menu7", 0x4e989, 0x0, IMGLEN1),
+ ("menu8", 0x4ea89, 0x0, IMGLEN1),
+ ("menu9", 0x4e889, 0x0, IMGLEN1),
+ ("mainmenu", 0x4c7f9, 0x0, IMGLEN1),
+ ("mainmenu-ch", 0x4f589, 0x0, IMGLEN1),
+ ("jpgx", 0x4b744, 0x0, IMGLEN16), # mod13
+ ("menu0", 0x4daf9, 0x0, IMGLEN1),
+ ],
+ [ # data buffers: fileoffset, start, end
+ (0x1b02 + 4, table_addr, table_addr + 0x28a), # Menu bitmap indices?
+ (0x1874 + 4, table_addr, table_addr + 0x28a), # Menu bitmap indices?
+ (0x53557, 0xfd7, 0xfd7 + 64),
+ ],
+ [ # Dynamic applet load: reloc, fileoffset, , size
+ (0x14e7, 0x0e54, 15 )
+ ]
+ ],
+ 'silver' : [
+ [ # special code segments: fileoffset, start, end
+ (0x2c0, 0x1934, 0x19f2),
+ (0x37e, 0x1003, 0x1270),
+ (0x662, 0x1280, 0x12d8),
+ ],
+ [],
+ [],
+ [],
+ ],
+ 'pink' : [
+ [ # code segments:
+ (0x2f0, 0x1934, 0x19f2),
+ (0x3ae, 0x1003, 0x1270),
+ (0x69c, 0x1280, 0x12d1),
+ (0x2fc0, 0x1800, 0x189d), # USB main loop, -> mod18_145b
+
+ (0x0e88, 0xce7 + 0x800, 0xce7 + 0x800 + 0x2c2),
+ ],
+ [ # images
+ ("img0", 0x5320b, 0x0, IMGLEN16),
+ ("img1", 0x54f4b, 0x0, IMGLEN1),
+ ("lowpower", 0x51a3b, 0x0, IMGLEN1),
+ ("img2", 0x4c244, 0x0, IMGLEN16),
+ ("title", 0x4f03b, 0x0, IMGLEN1),
+ ("title", 0x4f13b, 0x0, IMGLEN1),
+ ("title", 0x4f23b, 0x0, IMGLEN1),
+ ],
+ # data:
+ [],
+ # dynamic:
+ [
+ (0x14e7, 0x0e88, 15 )
+ ]
+ ],
+ 'focal' : [
+ [ # code segments:
+ (0x2e0, 0x1934, 0x19f2),
+ (0x39e, 0x1003, 0x1279),
+ (0x682, 0x1280, 0x12f3),
+ (0x3056, 0x1800, 0x189d), # USB main loop, -> mod17_145b
+
+ (0x0e88, 0xce7 + 0x800, 0xce7 + 0x800 + 0x2c2),
+ ],
+ [ # images
+ ("img0", 0x5320b, 0x0, IMGLEN16),
+ ],
+ # data:
+ [],
+ # dynamic:
+ [
+ (0x14e7, 0x0e88, 15 )
+ ]
+ ],
+ 'pearl' : [
+ [ # code segments:
+ (0x2e0, 0x1934, 0x19f2),
+ (0x39e, 0x1003, 0x1279),
+ (0x682, 0x1280, 0x12f3),
+ (0x3056, 0x1800, 0x189d), # USB main loop, -> mod17_145b
+
+ (0x0e88, 0xce7 + 0x800, 0xce7 + 0x800 + 0x2c2),
+ ],
+ [ # images
+ ("img0", 0x5320b, 0x0, IMGLEN16),
+ ],
+ # data:
+ [],
+ # dynamic:
+ [
+ (0x14e7, 0x0e88, 15 )
+ ]
+ ],
+ 'micca' : [
+ [ # code segments:
+ (0x2e0, 0x1934, 0x19f2),
+ (0x39e, 0x1003, 0x1279),
+ (0x682, 0x1280, 0x12f3),
+ (0x3056, 0x1800, 0x189d), # USB main loop, -> mod17_145b
+
+ (0x0e88, 0xce7 + 0x800, 0xce7 + 0x800 + 0x2c2),
+ ],
+ [ # images
+ ("img0", 0x5320b, 0x0, IMGLEN16),
+ ],
+ # data:
+ [],
+ # dynamic:
+ [
+ (0x14e7, 0x0e88, 15 )
+ ]
+ ],
+
+}
+
+RET = chr(0x22)
+LJMP = chr(0x02)
+LCALL = chr(0x12)
+
+bswap = lambda x: ( (x >> 8) & 0xff ) | ((x << 8) & 0xff00)
+
+class ProcEntry:
+ format = "<HHI"
+
+ def __init__(self):
+ self.start = 0
+ self.end = 0
+ self.offset = 0
+ self.size = struct.calcsize(self.format)
+
+ def fromBuffer(self, b):
+ start, end, self.offset, = struct.unpack(self.format, b)
+ self.start = bswap(start)
+ self.end = bswap(end)
+
+
+ def __repr__(self):
+ return "< %04x, %04x, %08x >" % (self.start, self.end, self.offset)
+
+def extract_code(data, fname):
+ out = data
+ outf = open(fname, "w")
+ outf.write(out)
+ outf.close()
+
+def write_ctl(name, offset, fileoffset, size = 0):
+ outf = open(name, "w")
+ outf.write("; control file -- autogenerated\n")
+ outf.write("; file offset: %08x\n" % fileoffset)
+ outf.write("# %04x\n" % offset)
+ outf.write("# %04x dump file offset: %08x\n" % (offset, fileoffset))
+ outf.write("o %04x\n" % offset)
+ if size:
+ outf.write("b %04x-%04x\n" % (offset, offset + size - 1))
+ outf.close()
+
+def exists(file):
+ try:
+ a = os.stat(file)
+ return 1
+ except:
+ return 0
+
+def generate_ctl(which, prefix, record, entries):
+ fname = "%s%02d.in" % (prefix, which)
+ if exists(fname):
+ print "%s exists, not creating" % fname
+ return
+
+ outf = open(fname, "w")
+ outf.write("; control file for %s%d.bin -- autogenerated\n" % (prefix, which))
+ outf.write("; file offset: %08x\n" % int(record.offset))
+ offset = 0x800 + record.start
+ outf.write("# %04x ----- SNIP : mod%d -----\n" % (offset, which))
+ outf.write("# %04x\n" % offset)
+ outf.write("# %04x dump file offset: %08x\n" % (offset, int(record.offset)))
+ outf.write("o %04x\n" % offset)
+ for i in entries:
+ outf.write("%s\n" % i)
+ outf.close()
+
+def build_tab(data, start, end):
+ l = []
+
+ offset = start
+
+ i = 0
+
+ while 1:
+ e = ProcEntry()
+ d = data[offset : offset + e.size]
+ e.fromBuffer(d)
+ if d == "-EndTbl-" or offset > end:
+ break
+ offset += e.size
+ l.append(e)
+ i += 1
+
+ return l
+
+val = lambda x: ord(x)
+
+# Some codes to scan for:
+
+scan_banksw = [
+ 0x74, val, 0x90, val, val, val, 0x19, val
+]
+
+scan_loadcode = [
+ 0x90, val, val, 0x7b, val, 0x7c, val, 0x7d, val, 0x7e, val , 0x7f, val
+]
+
+
+# Stolen from scantool:
+class Scanner:
+ def __init__(self, data, seq):
+ self.data = data
+ self.args = []
+ self.scansequence = seq
+
+ def scan(self, context, cb):
+ p = 0
+ n = 0
+ while p < len(self.data):
+ if type(self.scansequence[n]) == type(val):
+ args.append(val(data[p]))
+ n += 1
+ elif chr(self.scansequence[n]) == data[p]:
+ n += 1
+ else:
+ n = 0
+ args = []
+
+ if n == len(self.scansequence):
+ cb(context, args, p)
+ n = 0
+ args = []
+
+ p += 1
+
+def make_symentry(context, args, p):
+ e, offset = context
+ if args[3] in [0x12, 0x02]:
+ e.append("x %04x mod%d_%04x" % (offset + p - 4, args[0] + 1, (args[1] << 8) + args[2]))
+
+
+# TODO: Use scantool stuff
+def analyze(data, offset):
+ e = []
+
+ scanner = Scanner(data, scan_loadcode)
+ scanner.scan((e, offset), make_symentry)
+
+ return e
+
+def make_record(context, args, p):
+ e, rec = context
+ r = args[0] << 8 | args[1]
+ e.append("s %04x code_%04x" % (r, r + 0x800))
+ r = args[2] << 8 | args[3]
+ s = (args[4] << 16) | (args[5] << 8) | args[6]
+ e.append("# %04x load code from %06x to xmem:%04x" % (rec.start + 0x800 + p - 9, s, r))
+
+
+def analyze_bootblock(data):
+ rec = ProcEntry()
+
+ e = []
+ s = struct.unpack(">H", data[5:7])[0] # start code in flash
+ reloc = struct.unpack(">H", data[2:4])[0] # relocation
+
+ print hex(reloc), hex(s)
+
+ rec.start = reloc - s - 0x800
+ rec.offset = s
+
+ offset = reloc - s
+
+ e.append("b %04x-%04x" % (offset, (reloc - 1)))
+ e.append("l %04x start" % reloc)
+ e.append("l %04x jumptable" % (offset + 0x88))
+
+ # Just copy the scan hack -- no more scantool
+ scanner = Scanner(data, scan_loadcode)
+ scanner.scan((e, rec), make_record)
+
+ return rec, e
+
+
+def write_rawimage(d, fname):
+ outf = open(fname, "wb")
+ outf.write(d)
+ outf.close()
+
+try:
+ # Choose here which DPF to dump:
+ dpf = g_dpfs[sys.argv[1]]
+ f = open(sys.argv[2], "r")
+except (KeyError, IndexError):
+ print "Usage: %s <frameid>" % sys.argv[0]
+ print "where frameid is one of:"
+ for i in g_dpfs.keys():
+ print " ", i
+ print "No DPF specified given, running basic dump"
+ dpf = g_dpfs['default']
+ f = open("full_image.bin", "r")
+
+
+data = f.read()
+f.close()
+
+
+for i in dpf[0]:
+ o, start, end = i
+ end += 1
+ d = data[o:o + end - start]
+ extract_code(d, "code_%04x.bin" % start)
+ write_ctl("code_%04x.ctl" % start, start, o)
+
+for i in dpf[1]:
+ name, o, start, end = i
+ end += 1
+ d = data[o:o + end - start]
+ write_rawimage(d, "img_%s-%06x.raw" % (name, o))
+
+for i in dpf[2]:
+ o, start, end = i
+ end += 1
+ d = data[o:o + end - start]
+ extract_code(d, "data_%04x.bin" % o)
+ write_ctl("data_%04x.ctl" % o, start, o, end - start)
+
+for i in dpf[3]:
+ codeoffs, foffs, n = i
+ c0 = codeoffs
+ c1 = codeoffs - foffs
+ labels = {}
+ for j in range(n):
+ sz = [0,0]
+ offs = [0, 0]
+ o = foffs + j * 8
+ d = data[o:o + 8]
+
+ sz[0] = ord(d[0]) + (ord(d[1]) << 8)
+ offs[0] = foffs + ord(d[2]) + (ord(d[3]) << 8)
+ sz[1] = ord(d[4]) + (ord(d[5]) << 8)
+ offs[1] = foffs + ord(d[6]) + (ord(d[7]) << 8)
+
+ p = (c0 + j * 8 + 7, offs[0], sz[0], offs[1], sz[1])
+ print "! %04x dyn_%04x[%d], dyn_%04x[%d]" % p
+ labels[c1 + offs[0]] = "dyn_%04x" % offs[0]
+ labels[c1 + offs[1]] = "dyn_%04x" % offs[1]
+ for j in labels.keys():
+ print "l %04x %s" % (j, labels[j])
+
+format = ">HHBH"
+s = struct.unpack(format, data[:7])
+imem_loadaddr, code_startaddr, dummy, startcode = s
+
+l = build_tab(data, 0x88, startcode)
+
+print 80 * "-"
+
+start = l[0].offset
+d = data[0:start]
+extract_code(d, "dump00.bin")
+rec, entries = analyze_bootblock(d)
+generate_ctl(0, "dump", rec, entries)
+
+index = 1
+for i in l:
+ size = i.end - i.start
+ d = data[i.offset: i.offset + size]
+ print "[dump%d] %04x %04x %08x (%d)" % (index, i.start, i.end, i.offset, size)
+ extract_code(d, "dump%02d.bin" % index)
+ entries = analyze(d, i.start + 0x800)
+ generate_ctl(index, "dump", i, entries)
+ index += 1
+
+
+# No scantool here.
+# scantool.guess(scantool.MC8052, data, "dump")
+
+