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") + + | 
