You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Host OS: Ubuntu (please fill exact version, e.g. lsb_release -a)
mtkclient version/commit: (please fill — cd ~/mtkclient && git log -1 --oneline)
Summary
After a successful BROM → Kamakiri → DA stage-1 → DA_SYNC → EMI init → EMI-reconnect sequence, the very first status() call following a successfully-written BOOT_TO command (0x10008) returns a 12-byte XFlash status header where every single byte is shifted by exactly +1 (mod 256) relative to the expected header. This is not random USB noise — the shift is uniform across all 12 bytes and was reproduced identically (same resulting magic value) in two fully independent sessions.
Expected vs received header
Expected: ef ee ee fe 01 00 00 00 04 00 00 00 (magic=0xFEEEEEEF, type=1, length=4)
Received: f0 ef ef ff 02 01 01 01 05 01 01 01 (magic=0xFFEFEFF0)
Standard flow up through EMI init completes successfully (EMI init status: 0x0).
send_emi() triggers the expected USB disconnect (USBError(5, 'Input/Output Error'), Device disconnected) — this matches the existing # Disconnect after EMI is expected! comment in the code, so this part is not itself the bug.
After DA reinitializes USB, boot_to() is called for stage-2.
xsend(self.cmd.BOOT_TO) — the header write itself sometimes needs a few retries (USB not immediately ready after the EMI-reconnect), but once EP_OUT is valid again, usbwrite() succeeds (xsend result: True, BOOT_TO command sent).
The immediately following self.status() read gets the shifted header above instead of the expected 0xFEEEEEEF magic → "Status error: Wrong magic" → boot_to() fails → "Failed to upload da."
What has been ruled out
Python-level bug in mtkclient: added raw-byte logging directly inside usbread(), immediately after the underlying EP_IN.read() call (dt = epr(sz)), before any parsing/unpacking. The +1-shifted bytes are already present at that exact point — confirmed against dozens of prior, fully correct status() reads earlier in the same session using the identical single-byte read path. This rules out unpack(), buffering, or any queue/caching bug in the Python code.
Stale libusb-level internal queue: usbread()'s self.queue mechanism only gets populated in "fast" mode (self.fast == True), which is only enabled later via reinit()/set_fast_mode() after stage-2 is already running — at the point of this failure, self.fast is still False, so this queue is empty and not implicated.
Wrong USB endpoint selection: lsusb -v confirms Interface 1 (CDC Data, class 10) has EP 0x81 IN / EP 0x01 OUT, exactly matching what connect() selects via bInterfaceClass == devclass — Interface 0 (Communications, class 2) has no OUT endpoint at all, ruling out an interface mix-up.
A leftover/duplicate process competing for the USB device: checked via ps aux/lsof/fuser — ruled out for the specific captures where this was reproduced.
A local retry/off-by-one bug in our reconnect loop: rolling back all local retry-logic patches to xsend() (git checkout to a clean pre-patch state) and re-testing did not change the underlying "Wrong magic" behavior when it did occur, and actually reached WRITING far faster on the clean code (attempt unpack requires a buffer of 12 bytes on unlocking the bootloader #7 vs. hundreds of attempts with the heavier retry logic) — so the issue is not caused or fixed by our local retry additions.
What has NOT been fully ruled out
Kernel-level / xHCI-controller-level corruption below libusb (attempted usbmon/Wireshark capture on usbmon1, but the phone's BROM window is only ~200-300ms per cycle, and we were not able to reliably capture the exact failing packet during the capture windows attempted so far).
A possible power-stability issue in the phone specifically during/after DRAM (EMI) calibration, which several other users may have also hit under different symptom names (e.g. unpack requires a buffer of 12 bytes errors reported around EMI/DA stage-2 on other MT676x/MT678x devices).
Question
Is this a known DA-side (XFlash) or USB-controller-level quirk specifically tied to the EMI-reconnect → BOOT_TO transition on MT6769/Helio G88 (or MT676x family more broadly)? Has anyone seen a uniform +1 byte-shift pattern like this before, and if so, is there a known workaround (e.g. a specific delay, a different reconnect sequence, or a DA/preloader version known to avoid it)?
Happy to provide the full usbmon capture, complete debug logs, or test any suggested patch — this has been reproduced consistently across many independent sessions.
Device
selene, model 21061119DG0x707, HW subcode0x8a00, HW version0xca00lsb_release -a)cd ~/mtkclient && git log -1 --oneline)Summary
After a successful BROM → Kamakiri → DA stage-1 → DA_SYNC → EMI init → EMI-reconnect sequence, the very first
status()call following a successfully-writtenBOOT_TOcommand (0x10008) returns a 12-byte XFlash status header where every single byte is shifted by exactly +1 (mod 256) relative to the expected header. This is not random USB noise — the shift is uniform across all 12 bytes and was reproduced identically (same resulting magic value) in two fully independent sessions.Expected vs received header
Byte-by-byte delta (computed, not eyeballed):
All 12 bytes: delta == +1, no exceptions.
Reproduction context
EMI initcompletes successfully (EMI init status: 0x0).send_emi()triggers the expected USB disconnect (USBError(5, 'Input/Output Error'),Device disconnected) — this matches the existing# Disconnect after EMI is expected!comment in the code, so this part is not itself the bug.boot_to()is called for stage-2.xsend(self.cmd.BOOT_TO)— the header write itself sometimes needs a few retries (USB not immediately ready after the EMI-reconnect), but onceEP_OUTis valid again,usbwrite()succeeds (xsend result: True,BOOT_TO command sent).self.status()read gets the shifted header above instead of the expected0xFEEEEEEFmagic →"Status error: Wrong magic"→boot_to()fails →"Failed to upload da."What has been ruled out
usbread(), immediately after the underlyingEP_IN.read()call (dt = epr(sz)), before any parsing/unpacking. The +1-shifted bytes are already present at that exact point — confirmed against dozens of prior, fully correctstatus()reads earlier in the same session using the identical single-byte read path. This rules outunpack(), buffering, or any queue/caching bug in the Python code.usbread()'sself.queuemechanism only gets populated in "fast" mode (self.fast == True), which is only enabled later viareinit()/set_fast_mode()after stage-2 is already running — at the point of this failure,self.fastis stillFalse, so this queue is empty and not implicated.lsusb -vconfirms Interface 1 (CDC Data, class 10) has EP 0x81 IN / EP 0x01 OUT, exactly matching whatconnect()selects viabInterfaceClass == devclass— Interface 0 (Communications, class 2) has no OUT endpoint at all, ruling out an interface mix-up.ps aux/lsof/fuser— ruled out for the specific captures where this was reproduced.WRITINGfar faster on the clean code (attempt unpack requires a buffer of 12 bytes on unlocking the bootloader #7 vs. hundreds of attempts with the heavier retry logic) — so the issue is not caused or fixed by our local retry additions.What has NOT been fully ruled out
usbmon/Wireshark capture onusbmon1, but the phone's BROM window is only ~200-300ms per cycle, and we were not able to reliably capture the exact failing packet during the capture windows attempted so far).unpack requires a buffer of 12 byteserrors reported around EMI/DA stage-2 on other MT676x/MT678x devices).Question
Is this a known DA-side (XFlash) or USB-controller-level quirk specifically tied to the EMI-reconnect → BOOT_TO transition on MT6769/Helio G88 (or MT676x family more broadly)? Has anyone seen a uniform +1 byte-shift pattern like this before, and if so, is there a known workaround (e.g. a specific delay, a different reconnect sequence, or a DA/preloader version known to avoid it)?
Happy to provide the full
usbmoncapture, complete debug logs, or test any suggested patch — this has been reproduced consistently across many independent sessions.