#!/usr/bin/python -t
# -*- coding: iso-latin-1 -*-
import vars
import os
import sys
import string
import bdi
import time
debug_level = 1
chunkfile = '/bdi/chunk.%d' % os.getpid()
flash_page = 0x40000
class FlashSizeTooBig(Exception):
pass
class FlashError(Exception):
pass
def StripChunk(chunk, what='\xff'):
"""Löscht im Flash-Sektor 'chunk' die letzten Bytes, die den Wert
'what' haben. Normalerweise also 0xff am Ende.
Wir müssen diese Bytes nicht erst brennen, da nach einem
EraseFlashSector() sowieso 0xff im Sektor steht."""
n = len(chunk)
while n>0:
if chunk[n-1] != what:
break
n = n - 1
return chunk[:n]
def EraseFlashSector(addr):
"""Löscht einen physikalischen Flash-Sektor bei Adresse 'addr'."""
if vars.get('debug') >= debug_level+1:
print " x: lösche Flash-Sektor" % addr
res = bdi.cmd("erase 0x%x" % addr)
if string.find(res,'failed') != -1:
raise FlashError, "Kann Flash bei 0xx nicht löschen" % addr
def BurnFlashSector(addr,chunk,musterase=1):
"""Flasht einen Flash-Sektor 'chunk' physikalisch in den Flash ab
Adresse 'addr'"""
chunk = StripChunk(chunk)
if len(chunk)==0:
# don't flash empty sectors
return
# Erase block if necessary
if musterase:
if vars.get("flash_fast"):
testchunk = GetFlashSector(addr,32)
testchunk = StripChunk(testchunk)
if len(testchunk) > 12:
EraseFlashSector(addr)
else:
EraseFlashSector(addr)
if vars.get("flash_fast") and (len(chunk) == 12):
# we've been asked to not burn empty sectors
return
fname = vars.get('tftpboot')+chunkfile
try:
# Create a file that is accessible for the TFTP daemon and the BDI 2000
f = open(fname,'wb')
f.write(chunk)
f.close()
os.chmod(vars.get('tftpboot')+chunkfile, 0666)
# Burn chunk of data into flash
if vars.get('debug') >= debug_level+1:
print " x: brenne %d Bytes ins Flash" % (addr, len(chunk))
res = bdi.cmd("prog 0x%x %s BIN" % (addr, chunkfile))
finally:
os.unlink(fname)
if string.find(res,'failed') != -1:
raise FlashError,"Flashen schlug fehl bei 0xx" % addr
def GetFlashSector(addr,size):
if vars.get('debug') >= debug_level+1:
print " x: lade %d Bytes von Flash" % (addr, size)
# Create a world-writable file that the TFTP daemon and bdi2000 can write to
f = open(vars.get('tftpboot')+chunkfile,'wb')
f.close()
os.chmod(vars.get('tftpboot')+chunkfile, 0666)
# Place memory dump into file
res = bdi.cmd("dump 0x%x 0x%x %s" % (addr, size,chunkfile) )
if string.find(res,'failed') != -1:
raise FlashError, "Lesen vom Flash schlug fehl bei x" % addr
# Read file and delete it
f = open(vars.get('tftpboot')+chunkfile,'rb')
chunk = f.read()
f.close()
os.unlink(vars.get('tftpboot')+chunkfile)
return chunk
def CompareFlash(addr,chunk):
chunk = '\xff'
# Memory-Bereich überprüfen
if len(chunk) >= 64:
chunk2 = bdi.getmem(addr, 64)
if chunk[:64] != chunk2:
return 1
# Compare Checksum
s = "mc 0x%x %d" % (addr, len(chunk))
print s
s = bdi.cmd(s)
s = s[:-2]
print s
csum = 0
for c in chunk:
csum = csum + ord(c)
print "%x" % csum
# Compare full sector
# XXX
def BurnFileToFlash(addr, file, maxsize=None):
f = open(file, 'rb')
totalsize = os.stat(file).st_size
if vars.get('debug') >= debug_level:
print " Image:", file
print " Bytes:", totalsize
print " Max: ", maxsize
if maxsize and totalsize>maxsize:
raise FlashSizeTooBig
count = 0
starttime = time.time()
while 1:
chunk = StripChunk(f.read(flash_page))
if len(chunk)==0:
break
if vars.get('flash_compare'):
if vars.get('debug') >= debug_level:
t = time.time()-starttime
if count == 0:
print " x: bereits geflasht? %0.1f %%" % (addr,count*100.0/totalsize)
else:
print " x: bereits geflasht? %0.1f %% - %.1f Sekunden" % (addr,count*100.0/totalsize, t)
# First read 64 characters
chunk2 = StripChunk(bdi.getmem(addr, 64))
if chunk[:len(chunk2)]==chunk2:
# then read whole page
chunk2 = StripChunk(GetFlashSector(addr,len(chunk)))
if chunk==chunk2:
if vars.get('debug') >= debug_level:
print " x: bereits geflasht!" % addr
addr = addr + flash_page
count = count + flash_page
continue
else:
if vars.get('debug') >= debug_level:
t = time.time()-starttime
if count == 0:
print " x: %0.1f %%" % (addr, count*100/totalsize)
else:
print " x: %0.1f %% - %.1f Sekunden" % (addr,count*100.0/totalsize, t)
chunk2 = "need_erase"
BurnFlashSector(addr, chunk, chunk2 != "")
addr = addr + flash_page
count = count + flash_page
def GetFileFromFlash(addr, size, file, strip=1):
if vars.get('debug') >= debug_level:
print " Destination:", file
print " Max bytes: ", size
# Create a world-writable file that the TFTP daemon and bdi2000 can write to
outf = open(file,'wb')
starttime = time.time()
count = 0
while count < size:
if vars.get('debug') >= debug_level:
t = time.time()-starttime
if count == 0:
print " x: %0.1f %%" % (addr, count*100/size)
else:
print " x: %0.1f %% - %.1f Sekunden" % (addr,count*100.0/size, t)
chunk = GetFlashSector(addr, flash_page)
addr = addr + flash_page
count = count + flash_page
if strip and (count == size):
chunk = StripChunk(chunk)
outf.write(chunk)
outf.close()
if __name__ == '__main__':
def usage(lvl=1, txt=''):
if txt != '': print txt
print "Usage: burner.py "
print " burner.py /tftpboot/zImage 0x40000"
sys.exit(1)
vars.load()
import getopt
try:
opts, args = getopt.getopt(sys.argv[1:], "hN", ["help", "nocompare"])
except getopt.GetoptError:
# print help information and exit:
usage(1)
output = None
for o, a in opts:
if o in ("-h", "--help"):
usage(0)
if o in ("-N", "--nocompare"):
vars.set('flash_compare', 0)
if len(args) < 2: usage(1, 'missing arguments')
file = args[0]
if file=='': usage(1,'Erstes Argument muß eine Datei sein')
# Check and normalize load address
addr = args[1]
if addr=='': usage(1,'Zweites Argument muß eine Hexadezimalzahl sein')
if addr[0:2] == '0x': addr = addr[2:]
try:
addr = int(addr,16)
except:
usage(1,'Zweites Argument muß eine Hexadezimalzahl sein')
if addr % flash_page != 0: usage(1, "Zieladresse muß Vielfaches von %x sein" % flash_page)
vars.set('flash_compare',0)
BurnFileToFlash(addr, file)