#!/c/Python25/python import serial from struct import pack from struct import unpack import re import time import sys import ConfigParser # Either write_memory or read_memory has bytes swapped. # Dunno why. # Check for correct behavior with PEEDI. FT_APPLICATION = 0xAA FT_CSF = 0xCC FT_DCD = 0xEE DS_8 = 0x08 DS_16= 0x10 DS_32= 0X20 commands = { 'header' : "BBIBIBBBBB", 'write_memory': ">BBIBBBBBIB", 'get_status' : pack(">BBBBBBBBBBBBBBBB", 0x05, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 'write_file' : ">BBIBIBBBBB", } class mySerial(serial.Serial): # def write(self, stuff): # serial.Serial.write(self, stuff) def readline(self): stuff = serial.Serial.readline(self) if (len(stuff) > 0): #print ">>> %s"%stuff, pass return stuff def read_memory(ser, address, size, numwords = 1): cmd = pack(commands['read_memory'], 0x01, 0x01, # read command address, size, numwords, 0, 0, 0, 0, 0); print "writing..." ser.write(cmd) print "reading..." ack_str = ser.read(4); (ack) = unpack(">I", ack_str) ack_res = unpack(">I", pack(">I", 0x56787856)) if (ack == ack_res): if (size == DS_8): sizeof = 1 if (size == DS_16): sizeof = 2 if (size == DS_32): sizeof = 4 result = ser.read(numwords*sizeof) result = unpack("<%dI"%numwords, result) else: raise ReadFailedError("oops, read failed, ack=0x%08x" % ack) return result def write_memory(ser, address, size, value): cmd = pack(commands['write_memory'], 0x02, 0x02, address, size, 0, 0, 0, 0, value, 0) print "W: %d %x %x" % (size, address, value) ser.write(cmd) ack_str = ser.read(4) if (len(ack_str) == 4): (ack0) = unpack(">I", ack_str) else: raise WriteFailedError("Bad ACK when trying to write to address %08x: No Response" % address) #print "0x%08x"%(ack0) try: ack_str = ser.read(4) (ack0) = unpack(">I", ack_str) #print "0x%08x"%(ack0) except: raise WriteFailedError("Bad ACK when trying to write to address %08x: ACKed, but ACKed a fail response." % address) def get_status(ser): cmd = commands['get_status'] ser.write(cmd) result = ser.read(4) success = False if (len(result) == 4): # Successful get status. probably c = result[0] success = True for i in range (4): if (result[i] != c): success = False result = (ord(c)) else: raise CantGetStatusError("Bad Response code: len = %d, code = %s" %(len(result), result)) if (not success): raise CantGetStatusError("Bad Response code") return result def print_status(status): print "Status = 0x%02x"%status def get_header(address): app_start = address app_barker = 0xb1 csf_ptr = 0 dcd_ptr_ptr = address-24 srk_ptr = 0 dcd_ptr = 0 app_dest_ptr= 0 header = pack(commands['header'], app_start, app_barker, csf_ptr, dcd_ptr_ptr, srk_ptr, dcd_ptr, app_dest_ptr, 0x0) f = open('header.generated.bin', "wb"); f.write(header) f.close() return header def write_file(ser, address, filename, filetype = FT_APPLICATION): header = get_header(address) file = open(filename, "rb") filestring = file.read() file.close() write_file_from_data(ser, address - len(header), header + filestring, filetype) def write_file_from_data(ser, address, filestring, filetype = FT_APPLICATION): nbytes = len(filestring) print "Writing %d bytes" % nbytes cmd = pack(commands['write_file'], 0x04, 0x04, address, 0x00, nbytes, 0, 0, 0, 0, filetype) ser.write(cmd) result = ser.read(4) # print "%08x" % unpack(">I", result) ser.write(filestring) # write the file def run_script(ser, script_filename): try: f = open(script_filename, "r") except: raise Error("Could not open file %s" %script_filename) lines = f.readlines() print "Running init script with %d lines" % len(lines) for line in lines: re.sub(';.*$', line, '') m = re.search('^\s*mem\s+write(\d+)\s+([0-9a-fA-Fx]+)\s+([0-9a-fA-Fx]+)', line) if (m != None): bits_s = m.group(1) address_s = m.group(2) value_s = m.group(3) if (bits_s == '8'): bits = DS_8 elif (bits_s == '16'): bits = DS_16 elif (bits_s == '32'): bits = DS_32 address = eval(address_s) value = eval(value_s) write_memory(ser, address, bits, value) # Run the factive command # check to see if the BBT exists. def factive_nand(ser): done = False; ser.write("factive nand\n") bbt_found = False cnt = 0 while (not done): line = ser.readline() m = re.search(".*No BBT table found.*", line) if (m != None): bbt_found = False done = True waitforprompt(ser) m = re.search(".*Found version ? .*at block.*", line) if (m != None): bbt_found = True done = True waitforprompt(ser) cnt = cnt+1 if (cnt > 50): raise NoRedbootPromptError("No redboot prompt during factive.") return bbt_found class WriteFailedError(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) class ReadFailedError(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) class NoRedbootPromptError(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) class CantGetStatusError(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) def nand_scan_r(ser): ser.write("nand scan -r\n") waitforprompt(ser) def romupdate(ser): ser.write("romupdate\n") waitforprompt(ser) def get_ip_address(ser): ser.write("ip_address -b\n") cnt = 0 done = False success_re = 'IP: (\d+\.\d+\.\d+\.\d+)/(\d+\.\d+\.\d+\.\d+), Gateway: (\d+\.\d+\.\d+\.\d+).*' failure_re = 'Failed.*$' max_tries = 3 this_try = 0 ip = None netmask = None gw = None while (not done): if (this_try < max_tries): cnt = cnt + 1 line = ser.readline() m = re.search(success_re, line) if (m != None): done = True ip = m.group(1) netmask = m.group(2) gw = m.group(3) m = re.search(failure_re, line) if (m != None): # found the failure string. # Try fetching an IP address again. waitforprompt(ser) ser.write("ip_address -b\n") this_try = this_try + 1 else: raise NoIpAddressError waitforprompt(ser) return (ip, netmask, gw) #def program_filesystem(ser, tftp_ip_address, image_filename): # ser.write("load -v -r -b 0x100000 -h %s image_filename\n" % (tftp_ip_address, image_filename)) # done = False # while (not done): # def waitforprompt(ser): done = False cnt = 0 while (not done): ser.write("\n") prompt = ser.readline() if (len(prompt) == 0): print ".", sys.stdout.flush() if (prompt.startswith("RedBoot>")): done = True cnt = cnt + 1 if (cnt > 50): error = True raise NoRedbootPromptError print sys.stdout.flush() def open_serial(com_port): ser = mySerial( port=com_port, baudrate=115200, parity='N', stopbits=serial.STOPBITS_ONE, timeout=1, ) return ser if (len(sys.argv) != 2): print "Usage: serial-bootloader.py " sys.exit(1) platform = sys.argv[1] config = ConfigParser.RawConfigParser() config.read("serial-bootloader.cfg") try: com = config.get('common', 'com_port') image_filename = config.get(platform, 'image') init_script = config.get(platform, 'ddr2_init_script') load_address = eval(config.get(platform, 'ddr2_load_address')) except: print "Error: missing some configuration options for platform %s" % platform sys.exit(1) try: print "opening '%s'" % com ser = open_serial(com) if (ser != None): print "Opened serial port %s" % ser else: print "Couldn't open serial port %s" % com sys.exit(1) except: print "Error: couldn't open serial port %s" % com sys.exit(1) done = False while(not done): try: ser.flushOutput() ser.flushInput() status = get_status(ser) if (status == 0): print "Bad Status result. Try resetting the board." time.sleep(1) else: done = True print "Connected!" except CantGetStatusError: print "Waiting for system to respond." # Initializing the DDR2 run_script(ser, init_script) status = get_status(ser) # Do sanity check to see if we can read and write to DDR try : write_memory(ser, 0x80000010, DS_32, 0xdeadbeef) cmp = read_memory(ser, 0x80000010, DS_32) cmp = cmp[0] if (cmp != 0xdeadbeef): print "Error comminicating with DDR2. Wrote %08x, but read %08x" % (0xdeadbeef, cmp) sys.exit(-1) except WriteFailedError: print "Error comminicating with DDR2. No ack." sys.exit(-1) # Load the program try: write_file(ser, load_address, image_filename) except WriteFailedError: print "Write Failed. Perhaps you're trying to program a fab4 with a baby's load address?" try: get_status(ser) except: # This fails sometimes. I don't know why, but if we got this far # the programming should be okay. pass print "Waiting for redboot prompt." try: waitforprompt(ser) except: "Couldn't find redboot prompt. Bailing." sys.exit(-1) print "Redboot started." print "Checking for BBT." try: bbt_exists = factive_nand(ser) # Configure the NAND to get started. if (not bbt_exists): print "No BBT Exists. running nand scan -r" nand_scan_r(ser) # If no BBT, build it. else: print "\nBBT Exists. Fine" print "Writing redboot image" romupdate(ser) print "Writing Redboot Complete." # print "Getting ip address." # (ip, netmask, gw) = get_ip_address(ser) # print "got %s" % ip # print "Programming filesystem" # program_filesystem(ser) # print "Programming filesyste complete" except NoRedbootPromptError: print "Couldn't find redboot prompt. Something's broked:" sys.exit(1)