Source:/system/bin/recovery from firmware/na1-stock-recovery.img ramdisk, run in chroot on TWRP v2.5. Raw log: firmware/strace-stock-recovery.log (3268 lines).
Display Initialization — Authoritative Sequence
Step
Syscall
fd
Detail
1
openat("/dev/graphics/fb0", O_RDWR|O_CLOEXEC)
0
Main fb0 handle
2–3
ioctl(FBIOGET_FSCREENINFO / VSCREENINFO)
0
Read screen params
4
mmap(21209088, MAP_SHARED)
0
Full double-buffer (7552×2808)
5–8
Open fb0 again → read geometry → close
12
ebc helper (geometry only)
9
openat("/dev/ebc", O_RDWR)
12
EPDC control device
10
mmap(10513152, MAP_SHARED)
12
ebc pixel buffer (7488×1404, pixel-exact)
11
ioctl(12, 0x700c) EBC_SEND_UPDATE
12
Init/clear — BEFORE blank
12
ioctl(0, FBIOBLANK, 4)
0
FB_BLANK_POWERDOWN
13
ioctl(0, FBIOBLANK, 0)
0
FB_BLANK_UNBLANK
14–15
ioctl(12, 0x700c) EBC_SEND_UPDATE ×2
12
Content updates
What stock code does NOT do
FBIOPUT_VSCREENINFO — never called
FBIOPAN_DISPLAY — never called
Any sysfs writes to EPDC nodes
EBC_WAIT_UPDATE (0x700d) — not during init
EBC_CLEAR (0x700e) — never called
Critical Finding: Stock Binary Also Failed in TWRP Environment
When the stock recovery binary was run in a chroot inside TWRP (with TWRP process SIGSTOP’d), it completed its full display init sequence but produced no visible display change. This proved definitively that the display problem was NOT a userspace ioctl issue — the problem was in the kernel boot environment (missing waveform firmware file at /waveform/eink_waveform.wbf). See Research: A2 Waveform Mode for the root cause and fix.
Input Device Map
Device
Identity
TWRP use
event0
Power + Back button (KEY_POWER, KEY_BACK)
Use
event1
Capacitive touchscreen — MT type B (ABS_MT_SLOT, POSITION_X/Y, TRACKING_ID)
Expected behaviour — re-root using Phase 02 procedure
R10 — Onyx Telemetry
Severity
Trigger
Mitigation
🟡 Medium
Unblocked network on test device
Install AFWall+ immediately after rooting. Block all Onyx cloud services during development.
R11 — GPL Compliance
Severity
Trigger
Mitigation
🟡 Medium
Publishing firmware that contains Onyx kernel binary
Do not redistribute modified boot.img binaries in a way that implies GPL compliance. Onyx has not published GPL-compliant kernel sources. Note kernel binary status in all releases.
Always check image size vs partition size from Phase 01 partition table before flashing any NA2-derived image onto NA1.
R06 — Incorrect fstab Block Paths
Field
Value
Severity
🟠 High
Trigger
Booting NA2 system with UFS paths on NA1 eMMC
Phase 05 core task. Never flash an un-patched system/vendor from NA2. The fstab must be rewritten for eMMC block devices before use on NA1.
R07 — Incremental OTA on Rooted Device
Field
Value
Severity
🟠 High
Trigger
OTA update applied on Magisk-rooted device
Incremental OTA will not install cleanly on a rooted device (partition hash mismatch). Use only full firmware images. Block OTA in AFWall+ during development.
R08 — Accidental Userdata Wipe in TWRP
Field
Value
Severity
🟠 High
Trigger
Wrong option selected in TWRP menu on e-ink display
TWRP recovery menu interaction is slow on e-ink. Proceed slowly and confirm each action. The wipe data operation is irreversible without a backup.
ABL v2.0 — raw MmioRead32(0x03069004) on unmapped TLMM page → data abort
When ABL crashes before USB is initialized, no software EDL trigger is available. Device appears dead: red LED on, no USB enumeration, no 9008. Only recovery path: drain battery completely (~13 h from 45%) → cold PBL boot with hardware EDL cable.
Rules
Never use raw MmioRead32/MmioWrite32 in ABL without GCD memory mapping via gDS->GetMemorySpaceDescriptor + AddMemorySpace + SetMemorySpaceAttributes(EFI_MEMORY_UC)
Even with GCD mapping, TLMM flat address range (0x03000000–0x0306FFFF) is XPU-blocked from ABL — causes indefinite bus stall. Use south tile address (0x03100000+) instead
Before flashing any new ABL, identify the last known-good binary. First 9008 session after a bad flash MUST restore last known-good, not the untested new version
Always use tools/abl-build — never build or sign manually. Script enforces qtestsign -v 5
EDL 9008 (software-triggered via adb reboot edl) is the only recovery path. 900E (D+/GND cable short) can only dump memory — it cannot flash partitions. Always keep a working OS on the device. Never flash boot without a verified backup.
R04 — Wrong EDL Programmer
Field
Value
Severity
🔴 Critical
Trigger
Using NA2 UFS programmer on NA1 eMMC
Always confirm target device before selecting programmer. NA1 programmer:prog_emmc_ufs_firehose_Sdm636_ddr.elf. NA2 uses a UFS programmer — incompatible with NA1’s eMMC.
Never flash XBL or ABL from NA2 onto NA1. These partitions are storage-type-aware. A UFS bootloader on eMMC hardware = permanent brick.
Never touch the xbl partition. ABL failure is recoverable via EDL (XBL drops to 9008). XBL failure is a hard brick with no recovery path. Only flash the abl partition with custom builds from this project’s source.
XBL build path confirms: /work/disk5/sdm662/sdm662_android_rom/. Vendor: ro.board.platform=bengal. This is Snapdragon 662 (Bengal), a completely different SoC from NA1’s SDM636 (SDM660 family). The original project assumption was wrong.
Note Air 1
Note Air 2
SoC
SDM636 (sdm660)
SDM662 (bengal)
Kernel
4.4.x
4.19.157
Android
10 (SDK 29)
11 (SDK 30)
Partitions
static, single-slot
dynamic A/B + super
Encryption
FDE
FBE
Consequence: direct firmware port at partition level is not viable. Kernel, vendor HALs, and bootloaders are incompatible.
NA2 Firmware Chain
Version
Type
Size
URL MD5
v4.0
Full
1.84 GB
9bcffd50…
v4.0.2
Incremental
50 MB
91a889a3…
v4.1.1
Incremental
338 MB
04e3c7d5…
Served from http://firmware-us.boox.com/<md5>/update.upx. Decrypted with DeBooxUpx.py, extracted with payload-dumper-go v1.3.0 (A/B OTA format).
Onyx APKs — All Compatible with NA1
22 APKs extracted from system.img. All target SDK 29, minSDK 24 — compatible with NA1’s Android 10. Key apps: kreader2 v37913, knote2 v41957, kcb launcher v54255, ai-assistant v30165. Will run on NA1 without modification via sideload.
Cross-compiled ebc-probe.c with aarch64-linux-gnu-gcc -static. Two attempts, both caused kernel panic → 900E EDL dump mode:
Attempt 1: All phases (ioctl 0x7000–0x7024 with zeroed buffers) → kernel panic → 900E
Attempt 2: Phase 1 only (ioctl probe with zeroed buffers, no mmap) → kernel panic → 900E
Device recovered to TWRP automatically both times. The EBC driver’s ioctl handler does not tolerate probing with zeroed/dummy buffers when SurfaceFlinger/HWC is not running. ebc-probe cannot be used in TWRP. Running it requires a full Android boot.
sysfs Readout — Safe
Reading /sys/devices/sepdc/* is safe in TWRP (no crash):
Attribute
Value
panel_init
ok
waveform_version
onyx waveform sg
wf_status
99 (idle)
epdc_active_luts
[0x0][0x0][0x0][0x1] — 1 active LUT
update_disable
0 (updates enabled)
frame counter
245:243
Decision
Skip ioctl probing entirely — go straight to kernel NOP patch. Apply patch-kernel-waveform-transform.py to extract kernel, NOP the BL 0x427a8c at 0x41d410, repack boot.img, flash via TWRP, test A2 visually.
EFI_QCOM_PMIC_PON_PROTOCOL->GetPonReason() — unexpectedly hangs too
Conclusion: no UEFI protocol calls are safe from fastboot context. Detection must happen in LinuxLoaderEntry() before EnterFastboot() is called — same location as hall sensor code. The stock ABL does exactly this in its GetBootIntoMode function.
v2.4 remains last-known-good. v2.5 to be restored to v2.4 at next session start.