def verify(ser, path, flashsize, bootloadersize, destructive=False): try: f = open(path, "rb") except IOError: CHK(False, "'%s': can't open file" % path, 5) data = f.read() f.close() modem = XMODEM(None, None) if destructive: ser.write('v') #no prefixed bytes, since uploading a bootloader bootloadersize = 0x0000 else: ser.write('c') lines = [] resp = "" while len(lines) < 3: resp += get_response(ser) lines = resp.split('\r\n') CHK(lines[1].startswith("CRC:"), RESP_ERR, 3) testcrc = lines[1][9:] crc = int(modem.calc_crc(data)) # rest of the flash is 0xFF for i in xrange(flashsize - len(data) - bootloadersize): crc = modem.calc_crc('\xFF', crc) crc = hex(crc)[2:].upper() #extend to 4 chars crc = (4 - len(crc)) * "0" + crc print "CRC", crc, testcrc if testcrc == crc: INFO("Verify OK!") return testcrc == crc
def verify(ser, path, flashsize, bootloadersize, destructive=False): try: f = open(path, "rb") except IOError: CHK(False, "'%s': can't open file" % path, 5) data = f.read() f.close() modem = XMODEM(None, None) if destructive: ser.write("v") # no prefixed bytes, since uploading a bootloader bootloadersize = 0x0000 else: ser.write("c") lines = [] resp = "" while len(lines) < 3: resp += get_response(ser) lines = resp.split("\r\n") CHK(lines[1].startswith("CRC:"), RESP_ERR, 3) testcrc = lines[1][9:] crc = int(modem.calc_crc(data)) # rest of the flash is 0xFF for i in xrange(flashsize - len(data) - bootloadersize): crc = modem.calc_crc("\xFF", crc) crc = hex(crc)[2:].upper() # extend to 4 chars crc = (4 - len(crc)) * "0" + crc print "CRC", crc, testcrc if testcrc == crc: INFO("Verify OK!") return testcrc == crc
class MtkFlasher(object): BAUD = { "ls": 115200, "hs": 921600, "ss": 3000000, } MAGIC = 0x00052001 SECRET_MAGIC = 0x00052002 def __init__(self, port, speed, binpath=None, debug=False): self.speed = speed self.baud = self.BAUD[speed] self.port = port self.xm = XMODEM(self.getc, self.putc, "xmodem1k", "\xff") self.binpath = binpath or BIN_PATH self.tag = 0x1000 self.debug = debug def log(self, *args): if self.debug: print(*args) def getc(self, size, timeout=1): self.ser.timeout = timeout return self.ser.read(size) def putc(self, data, timeout=1): self.ser.write_timeout = timeout return self.ser.write(data) def xm_send(self, fd, msg=" Sending"): fd.seek(0, 2) length = fd.tell() fd.seek(0, 0) blocks = (length + 1023) / 1024 def callback(total, success, error): sys.stdout.write("\r%s... %d%%" % (msg, 100 * success // blocks)) sys.stdout.flush() self.xm.send(fd, callback=callback) print() def bootstrap(self, ): print("Opening port at 115200 baud...") self.ser = Serial(self.port, 115200) fname = "uart_%s.bin" % self.speed print("Sending baudrate switcher (%s)..." % fname) self.xm_send(open(os.path.join(self.binpath, fname), "rb")) self.ser.close() print("Reopening port at %d baud..." % self.baud) self.ser = Serial(self.port, self.baud) fname = "ated_%s.bin" % self.speed print("Sending ATED (%s)..." % fname) self.xm_send(open(os.path.join(self.binpath, fname), "rb")) def command(self, cmd, args=b"", magic=MAGIC): self.tag += 1 self.ser.timeout = 5 self.ser.write_timeout = 5 payload = struct.pack(">H", cmd) + args data = struct.pack(">IHH", magic, len(payload) + 2, self.tag) + payload crc = self.xm.calc_crc(data) self.ser.write(data + struct.pack(">H", crc)) reply = self.ser.read(8) reply_magic, reply_len, tag = struct.unpack(">IHH", reply) assert reply_magic == (magic | 0x80000000) assert tag == self.tag reply += self.ser.read(reply_len) assert len(reply) == reply_len + 8 crc = struct.unpack(">H", reply[-2:])[0] assert self.xm.calc_crc(reply[:-2]) == crc reply_cmd = struct.unpack(">H", reply[8:10])[0] assert reply_cmd == (cmd + 1) return reply[10:-2] def initialize(self): self.log(" cmd: initialize") reply = self.command(0x00) self.log(" returned:", reply.encode("hex")) def get_storage_info(self): self.log(" cmd: get_storage_info") reply = self.command(0x10) self.log(" returned:", reply.encode("hex")) unk1, unk2, flash_size, = struct.unpack(">III", reply) return {"size": flash_size} def erase(self, start, length): self.log(" cmd: erase(0x%x, 0x%x)" % (start, length)) reply = self.command(0x0a, struct.pack(">II", start, length)) self.log(" returned:", reply.encode("hex")) def erase_end(self): self.log(" cmd: erase_end") reply = self.command(0x0c) self.log(" returned:", reply.encode("hex")) def download(self, address, length): self.log(" cmd: download(0x%x, 0x%x)" % (address, length)) flags = 0x01000400 reply = self.command(0x02, struct.pack(">IIII", address, length, address + length, flags)) self.log(" returned:", reply.encode("hex")) def download_end(self): self.log(" cmd: download_end") reply = self.command(0x04) self.log(" returned:", reply.encode("hex")) # Orig uses 0x20000 but this provides more granular progress def erase_range(self, addr, length, blocksize=0x2000): for i in xrange(0, length, blocksize): self.erase(addr + i, min(blocksize, length - i)) if not self.debug: sys.stdout.write("\r Erasing... %d%%" % (100 * i // length)) sys.stdout.flush() self.erase_end() if not self.debug: print("\r Erasing... 100%") def write_file(self, addr, filename, erase=True): print("Writing to 0x%x: %s" % (addr, filename)) fd = open(filename, "rb") fd.seek(0, 2) length = fd.tell() fd.seek(0, 0) assert addr & 0xfff == 0 padded_length = (length + 0xfff) & ~0xfff if erase: self.erase_range(addr, padded_length) self.download(addr, length) self.xm_send(fd, " Writing") self.download_end() def read_efuse(self, off, length): assert (off & 0xf == 0) assert (length & 0xf == 0) self.log(" cmd: read_efuse") reply = self.command(0x04, struct.pack(">II", off, length), self.SECRET_MAGIC) self.log(" returned:", reply.encode("hex")) return reply[4:] def read_unique_id(self): self.log(" cmd: read_unique_id") reply = self.command(0x02, magic=self.SECRET_MAGIC) self.log(" returned:", reply.encode("hex")) return reply[4:] def get_mac(self): fuseblock = self.read_efuse(0, 0x10) return ":".join("%02x" % ord(c) for c in fuseblock[4:10])