diff options
Diffstat (limited to 'oncology/dpfhack_display/reverse')
-rw-r--r-- | oncology/dpfhack_display/reverse/Makefile | 76 | ||||
-rw-r--r-- | oncology/dpfhack_display/reverse/README | 169 | ||||
-rw-r--r-- | oncology/dpfhack_display/reverse/common.in | 213 | ||||
-rw-r--r-- | oncology/dpfhack_display/reverse/dump.py | 470 |
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") + + |