#!/usr/bin/env python3 """Minimal Qualcomm DIAG EFS2 client over a serial diag port. Packet layouts and opcodes replicate JohnBel/EfsTools exactly. Used to back up and replace policyman RF-band config on a rooted Sony Xperia 1 VI. """ import sys, os, time, struct, glob, serial DIAG_SUBSYS = 0x4B SUBSYS_EFS = 19 # EFS opcodes (EfsTools QcdmEfsCommand) HELLO, QUERY, OPEN, CLOSE, READ, WRITE = 0, 1, 2, 3, 4, 5 UNLINK, MKDIR, OPENDIR, READDIR, CLOSEDIR, STAT = 8, 9, 11, 12, 13, 15 # open flags O_WRONLY, O_RDONLY, O_CREAT = 0o1, 0o0, 0o100 # CRC-16 CCITT reflected (HDLC FCS-16) _TAB = [] for _i in range(256): _c = _i for _ in range(8): _c = (_c >> 1) ^ 0x8408 if (_c & 1) else (_c >> 1) _TAB.append(_c) def fcs16(data): fcs = 0xFFFF for b in data: fcs = (fcs >> 8) ^ _TAB[(fcs ^ b) & 0xFF] return (~fcs) & 0xFFFF def hdlc_encode(payload): crc = fcs16(payload) frame = bytes(payload) + struct.pack("= 3 and dec[0] == 0x00 and \ fcs16(dec[:-2]) == struct.unpack("= 4 and p[0] == DIAG_SUBSYS and p[1] == SUBSYS_EFS \ and struct.unpack(" ignore raise TimeoutError("no matching response for efs cmd %d" % efs_cmd) # ---- EFS operations ---- def hello(self): win, wbyte, ver = 0x100000, 0x100000, 1 body = struct.pack(" 1 else "probe" d = Diag() print("using diag port %s" % d.port) ver = d.hello() print("EFS hello ok, version=%d" % ver) if cmd == "probe": entries = d.listdir(TARGET_DIR) print("%s: %d entries" % (TARGET_DIR, len(entries))) for name, etype, size in entries: mark = " <== TARGET" if name in TARGETS else "" print(" %-40s type=%d size=%d%s" % (name, etype, size, mark)) for t in TARGETS: err, mode, size = d.stat("%s/%s" % (TARGET_DIR, t)) print("stat %s -> err=%d mode=%o size=%d" % (t, err, mode & 0xffff, size)) elif cmd == "backup": os.makedirs(BACKUP, exist_ok=True) for t in TARGETS: data = d.read_file("%s/%s" % (TARGET_DIR, t)) open("%s/%s" % (BACKUP, t), "wb").write(data) print("backed up %s (%d bytes)" % (t, len(data))) elif cmd == "write": for t in TARGETS: data = open("%s/%s" % (SRC, t), "rb").read() n = d.write_file("%s/%s" % (TARGET_DIR, t), data) print("wrote %s (%d bytes)" % (t, n)) elif cmd == "verify": ok = True for t in TARGETS: want = open("%s/%s" % (SRC, t), "rb").read() got = d.read_file("%s/%s" % (TARGET_DIR, t)) same = want == got ok = ok and same print("verify %s: %s (device %d bytes, source %d bytes)" % (t, "MATCH" if same else "DIFFER", len(got), len(want))) print("ALL VERIFIED" if ok else "MISMATCH!") d.s.close() if __name__ == "__main__": main()