def act_pack(args):
    args = loadconfigs(args, "pack")
    params = {}
    def cnn(v):
        if args[v] is None:
            print "Expected '%s' argument for sdb packing" % v
            sys.exit(1)
        return args[v]

    params["maintainer_name"] = cnn("maintainer")
    params["repository_url"] = args.get("repository","UNKNOWN")
    params["version"] = cnn("version")
    params["build_date"] = str(datetime.datetime.now())
    params["changeset_id"] = args.get("changeset","UNKNOWN")
    params["description"] = cnn("description")
    params["short_name"] = cnn("name")
    params["tool_versions"] = []
    if args["tool"] is None: args["tool"] = []
    for tl in args["tool"]:
        try:
            tool, version = tl.split("=")
            params["tool_versions"].append((tool, version))
        except ValueError:
            print "Invalid tool version specification '%s'. " % tl
            print "Expected 'toolname=version'"
            sys.exit(1)


    cell = SLCell.generate(params, args["elf"])
    oname = args.get("outfile", params["short_name"]+".sdb")

    if args["assetlist"] is not None:
        f = open(args["assetlist"],"r")
        for l in f.readlines():
            l = l.strip()
            if len(l) == 0 or l.startswith("#"): continue
            la = l.split()
            if len(la) != 4:
                print "Asset manifest syntax is <i/x> <addr/*> <name> <filename>"
                print "got: ", repr(la)
                sys.exit(1)
            intex, addr, name, filename = la
            if intex not in ["i","x"]:
                print "Incorrect location specifier for flash asset: allowed 'i' or 'x'"
                sys.exit(1)
            _add_asset(cell, {"internal": intex == "i", "name": name, "asset": filename, "addr": None if addr == "*" else addr})


    cell.save(oname)
def act_cloudflash(args):
    args = loadconfigs(args, "cloudflash")
    imgl = args["image"].split(":", 1)
    if len(imgl) != 2:
        print "bad image descriptor, expected ns:name"
    ithen = time.time()
    if args["verbose"]:
        print "Downloading image ",
        sys.stdout.flush()
    r = requests.get("http://cloud.storm.rocks/r/"+imgl[0]+"/"+imgl[1])
    if args["verbose"]:
        print "done (%.3f seconds)" %(time.time() - ithen)
    if len(r.content) == 0:
        print "Could not download image"
        sys.exit(1)
    with tempfile.NamedTemporaryFile() as ntf:
        try:
            ntf.write(r.content)
            ntf.flush()
            sl = sl_api.StormLoader(args.get("tty", None))
            sl.enter_bootload_mode()
            then = time.time()
            try:
                cell = SLCell.load(ntf.name)
            except:
                print "SDB image is corrupt"
                sys.exit(1)
            img = cell.get_raw_image()
            sl.write_extended_irange(cell.FLASH_BASE, img)
            now = time.time()
            if args["verbose"]:
                print "Wrote %d bytes in %.3f seconds" %(len(img), now-then)
            expected_crc = sl.crc32(img)
            written_crc = sl.c_crcif(cell.FLASH_BASE, len(img))
            if expected_crc != written_crc:
                print "CRC failure: expected 0x%04x, got 0x%04x" % (expected_crc, written_crc)
                sys.exit(1)
            elif args["verbose"]:
                print "CRC pass"
            sl.enter_payload_mode()
        except sl_api.StormloaderException as e:
            print "Fatal error:", e
            sys.exit(1)
def act_list_assets(args):
    args = loadconfigs(args, "assetlist")
    cell = SLCell.load(args["sdb"])
    iassets = cell.list_iassets()
    eassets = cell.list_eassets()
    def pr_assets_human(assets):
        print " # Address   Length  Name"
        for (i, a) in assets:
            print "{:>2d} 0x{:07x} 0x{:05x} {}".format(i, a["address"], a["length"], a["name"])
    def pr_assets_header(assets):
        s1s = []
        s2s = []
        s3s = []
        for (i, a) in assets:
            s1s.append(("#define ASSET_{}_NAME".format(a["name"].upper()),
                        "\"{}\"".format(a["name"])))
            s2s.append(("#define ASSET_{}_ADDR".format(a["name"].upper()),
                        "0x{:07x}".format(a["address"])))
            s3s.append(("#define ASSET_{}_LEN".format(a["name"].upper()),
                        "0x{:05x}".format(a["length"])))
        longest = max(len(i[0]) for i in (s1s+s2s+s3s))
        for i in s1s+s2s+s3s:
            print ("{:<%ds} {}" % longest).format(*i)

    if len(iassets) > 0:
        print "Internal flash assets"
        if not args["header"]:
            pr_assets_human(iassets)
        else:
            pr_assets_header(iassets)
    else:
        print "No internal flash assets"
    print ""
    if len(eassets) > 0:
        print "External flash assets"
        if not args["header"]:
            pr_assets_human(eassets)
        else:
            pr_assets_header(eassets)
    else:
        print "No external flash assets"
def act_flash_assets(args):
    try:
        args = loadconfigs(args, "assetflash")
        sl = sl_api.StormLoader(args.get("tty", None))
        sl.enter_bootload_mode()
        then = time.time()
        cell = SLCell.load(args["sdb"])
        for i, a in cell.list_iassets():
            body = a["contents"]
            if args["verbose"]:
                print "writing %s to iflash @ 0x%x (%d : 0x%x bytes)... " %\
                      (a["name"],a["address"],a["length"],a["length"]),
                sys.stdout.flush()
            sl.write_extended_irange(a["address"], body)
            if args["verbose"]:
                print "ok"
        for i, a in cell.list_eassets():
            body = a["contents"]
            if args["verbose"]:
                print "writing %s to xflash @ 0x%x (%d : 0x%x bytes)... " %\
                      (a["name"],a["address"],a["length"],a["length"]),
                sys.stdout.flush()
            sl.write_extended_xrange(a["address"], body)
            ecrc = sl.crc32(body)
            rcrc = sl.c_crcef(a["address"], a["length"])
            if ecrc != rcrc:
                print "CRC FAIL! (expected 0x%08x, got 0x%08x" % (ecrc, rcrc)
                sys.exit(1)
            if args["verbose"]:
                print "ok"
        now = time.time()
        if args["verbose"]:
            print "%.2f seconds" % (now-then)
        sl.enter_payload_mode()

    except sl_api.StormloaderException as e:
        print "Fatal error:", e
        sys.exit(1)
def act_flash(args, ftdi_device_id=None):
    try:
        args = loadconfigs(args, "flash")
        sl = sl_api.StormLoader(args.get("tty", None), device_id=ftdi_device_id)
        sl.enter_bootload_mode()
        then = time.time()
        cell = SLCell.load(args["sdb"])
        img = cell.get_raw_image()
        sl.write_extended_irange(cell.FLASH_BASE, img)
        now = time.time()
        if args["verbose"]:
            print "Wrote %d bytes in %.3f seconds" %(len(img), now-then)
        expected_crc = sl.crc32(img)
        written_crc = sl.c_crcif(cell.FLASH_BASE, len(img))
        if expected_crc != written_crc:
            print "CRC failure: expected 0x%04x, got 0x%04x" % (expected_crc, written_crc)
            sys.exit(1)
        elif args["verbose"]:
            print "CRC pass"
        sl.enter_payload_mode()
    except sl_api.StormloaderException as e:
        print "Fatal error:", e
        sys.exit(1)
def act_hexdump(args):
    args = loadconfigs(args, "hexdump")
    cell = SLCell.load(args["sdb"])
    print cell.get_hex_image()
def act_add_asset(args):
    args = loadconfigs(args, "assetadd")
    cell = SLCell.load(args["sdb"])
    _add_asset(cell, args)
    cell.save(args["sdb"])
def act_program_kernel_payload(args, ftdi_device_id=None):
    cache_file = '.cached_payload' if ftdi_device_id is None else '.cached_payload_{0}'.format(ftdi_device_id)
    try:
        eximage = open(cache_file,"r").read()
    except:
        eximage = None
    try:
        args = loadconfigs(args, "program")
        params = {}
        params["maintainer_name"] = "UNKNOWN"
        params["repository_url"] ="UNKNOWN"
        params["version"] = "UNKNOWN"
        params["build_date"] = str(datetime.datetime.now())
        params["changeset_id"] = "UNKNOWN"
        params["description"] = "UNKNOWN"
        params["short_name"] = "UNKNOWN"
        params["tool_versions"] = []
        cell = SLCell.generate(params, args["elf"])
        img = cell.get_raw_image()[0x40000:] #was 0x4...

        sl = sl_api.StormLoader(args.get("tty", None), device_id=ftdi_device_id)
        sl.enter_bootload_mode()
        print "Probing payload ELF for entry point..."
        _start = cell.locate_symbol("_start")
        if _start != None:
            print "Located _start at 0x%06x" % _start
            print "Setting entrypoint attribute"
            sl.c_sattr(1,"_start", [_start & 0xFF, (_start >> 8) & 0xFF, (_start >> 16) & 0xFF, (_start >> 24) & 0xFF ])
        else:
            print "Could not locate _start! This payload will not boot!"

        def wfull():
            print "Writing full payload..."
            idx = 0
            retries = 0
            then = time.time()
            while idx < len(img):
                endslice = idx + 0x200
                if endslice > len(img):
                    endslice = len(img)
                sl.write_extended_irange(0x50000 + idx, img[idx:endslice])
                expected_crc = sl.crc32(img[idx:endslice])
                written_crc = sl.c_crcif(0x50000 + idx, endslice-idx)
                if (expected_crc != written_crc):
                    #print ("expected page: ")
                    a = (" ".join("%02x" % ord(c) for c in img[idx:endslice]))
                    #print a
                    rpage = sl.read_extended_irange(0x50000 + idx, 0x200)
                    #print ("got page: ")
                    b = (" ".join("%02x" % ord(c) for c in rpage))
                    #print b
                    print ("slice crc mismatch at 0x%x"%(0x50000 + idx))
                    print "mismatches in bytes: ", [i/3 for i in xrange(len(b)) if a[i] != b[i]]
                    #sl.c_epage(0x50000+idx)

                    retries += 1
                    if (retries == 5):
                        print("hit max retries")
                        print("aborting. please report")
                        sys.exit(1)
                else:
                    retries = 0
                    idx += 0x200
            now = time.time()
            expected_crc = sl.crc32(img)
            written_crc = sl.c_crcif(0x50000, len(img))
            print "Image is 0x%x bytes long" % (len(img))
            if expected_crc != written_crc:
                print "CRC failure: expected 0x%04x, got 0x%04x" % (expected_crc, written_crc)
                sys.exit(1)
            print "Wrote and verified %d bytes in %.3f seconds" %(len(img), now-then)

        if eximage != None:
            excrc = sl.crc32(eximage)
            realcrc = sl.c_crcif(0x50000, len(eximage))
            if excrc != realcrc:
                print "Payload cached contents do not match (this will take longer)"
                wfull()
            else:
                newimg = img
                oldimg = eximage
                if len(newimg) % 512 != 0:
                        newimg += "\xFF"*(512 - (len(newimg)%512))

                if len(oldimg) < len(newimg):
                    old_end = len(oldimg) &~ 511
                    start_address = (0x50000 + old_end)
                    sl.write_extended_irange(start_address, newimg[old_end:])
                    oldimg = oldimg[:old_end]
                    oldimg += newimg[old_end:]

                assert len(oldimg) >= len(newimg)

                def fix_difference():
                    for idx in xrange(len(newimg)):
                        if oldimg[idx] != newimg[idx]:
                            page_address = idx &~511
                            real_address = page_address + 0x50000
                            if args["verbose"]:
                                print "Changed page at 0x%08x" % real_address
                            sl.c_wpage(real_address, newimg[page_address:page_address+512])
                           # oldimg[page_address:page_address+512] = newimg[page_address:page_address+512]
                            newoldimg = oldimg[:page_address] + newimg[page_address:page_address+512] + \
                                        oldimg[page_address + 512:]
                            return (True, newoldimg)
                    return (False, oldimg)

                then = time.time()
                for i in xrange(len(oldimg)+1):
                    changes, oldimg = fix_difference()
                    if not changes:
                        expected_crc = sl.crc32(newimg)
                        written_crc = sl.c_crcif(0x50000, len(newimg))
                        if expected_crc != written_crc:
                            print "CRC failure: expected 0x%04x, got 0x%04x" % (expected_crc, written_crc)
                            sys.exit(1)
                        elif args["verbose"]:
                            print "CRC pass"
                        print "Written and verified in %.2f seconds" % (time.time() - then)
                        break
                else:
                    raise sl.StormloaderException("Delta algorithm bug detected")
        else:
            print "No cached contents (this will take longer)"
            wfull()
        with open(cache_file,"w") as f:
            f.write(img)

        sl.enter_payload_mode()
    except sl_api.StormloaderException as e:
        print "Fatal error:", e
        sys.exit(1)
def act_delta(args, ftdi_device_id=None):
    args = loadconfigs(args, "flashdelta")
    sl = sl_api.StormLoader(args.get("tty", None), device_id=ftdi_device_id)
    sl.enter_bootload_mode()

    newcell = SLCell.load(args["newimg"])
    newimg = newcell.get_raw_image()

    def full_flash():
        then = time.time()

        #write the whole img
        sl.write_extended_irange(SLCell.FLASH_BASE, newimg)
        expected_crc = sl.crc32(newimg)
        written_crc = sl.c_crcif(SLCell.FLASH_BASE, len(newimg))
        if expected_crc != written_crc:
            print "CRC failure: expected 0x%04x, got 0x%04x" % (expected_crc, written_crc)
            sys.exit(1)
        elif args["verbose"]:
            print "CRC pass"
        sl.enter_payload_mode()
        if args["verbose"]:
            print "Written and verified in %.2f seconds" % (time.time() - then)
        return

    #We also permit an empty file to be specified as the old image
    #this represents null

    if not (os.path.exists(args["oldimg"]) and os.path.isfile(args["oldimg"])) or os.stat(args["oldimg"]).st_size == 0:
        if args["verbose"]:
            print "Old image is empty, doing full flash"
        full_flash()
        return

    oldcell = SLCell.load(args["oldimg"])
    oldimg = oldcell.get_raw_image()

    oldimgcrc = sl.crc32(oldimg)
    actualcrc = sl.c_crcif(sl.FLASH_FLOOR, len(oldimg))

    if oldimgcrc != actualcrc:
        print "Actual contents do not match expected image, this will take longer"
        full_flash()
        return

    if len(newimg) % 512 != 0:
            newimg += "\xFF"*(512 - (len(newimg)%512))

    if len(oldimg) < len(newimg):
        old_end = len(oldimg) &~ 511
        start_address = (sl.FLASH_FLOOR + old_end)
        sl.write_extended_irange(start_address, newimg[old_end:])
        oldimg = oldimg[:old_end]
        oldimg += newimg[old_end:]

    assert len(oldimg) >= len(newimg)

    def fix_difference():
        for idx in xrange(len(newimg)):
            if oldimg[idx] != newimg[idx]:
                page_address = idx &~511
                real_address = page_address + oldcell.FLASH_BASE
                if args["verbose"]:
                    print "Changed page at 0x%08x" % real_address
                sl.c_wpage(real_address, newimg[page_address:page_address+512])
               # oldimg[page_address:page_address+512] = newimg[page_address:page_address+512]
                newoldimg = oldimg[:page_address] + newimg[page_address:page_address+512] + \
                            oldimg[page_address + 512:]
                return (True, newoldimg)
        return (False, oldimg)

    then = time.time()
    for i in xrange(len(oldimg)+1):
        changes, oldimg = fix_difference()
        if not changes:
            expected_crc = sl.crc32(newimg)
            written_crc = sl.c_crcif(oldcell.FLASH_BASE, len(newimg))
            if expected_crc != written_crc:
                print "CRC failure: expected 0x%04x, got 0x%04x" % (expected_crc, written_crc)
                sys.exit(1)
            elif args["verbose"]:
                print "CRC pass"
            print "Written and verified in %.2f seconds" % (time.time() - then)
            break
    else:
        raise sl.StormloaderException("Delta algorithm bug detected")
    sl.enter_payload_mode()