Archives: Boox Knowledge Base

  • Device Facts — Note Air 1 (SDM636, eMMC, Android 10)

    Device Facts — Note Air 1 (SDM636, eMMC, Android 10)

    Note Air 1 — Hardware & Platform Facts

    Source: Device exploration phase (sessions 1–10), completed 2026-03-16. All facts confirmed from physical device via ADB/EDL.

    Identity

    FieldValue
    ro.product.deviceNoteAir
    ro.build.version.release10 (Android 10)
    ro.build.version.sdk29
    Firmware version3.5 (build 2023-12-12)
    SoCQualcomm Snapdragon 636 (SDM636)
    Platform codenamesdm660
    StorageeMMC (mmcblk0, 29.1 GB = ~32 GB chip, DX68MB, mfr ID 21)
    RAM3 GB
    CPUarm64-v8a (Kryo 260: 4×A73 + 4×A53)
    Kernel4.4.194-perf-gc7a75cf-dirty (built 2023-11-30)

    Treble & Partition Scheme

    FieldValue
    ro.treble.enabledtrue
    ro.vndk.version29
    /vendor partitionSeparate (dm-1, ext4, dm-verity)
    Dynamic partitionsNo — static single-slot
    A/B slotsNo — single slot, no slot_suffix
    EncryptionFDE (full-disk, dm-2)

    Partition Table (Key Partitions)

    NameOffsetSizeNotes
    xbl / xblbak0x040000003.5 MBXBL — NEVER FLASH
    boot0x0800000064 MBKernel + ramdisk
    recovery0x0C00000064 MBTWRP v3.7 currently
    system0x100000003 GBAndroid system (dm-0)
    vendor0xD0000000800 MBVendor HALs (dm-1)
    abl0x11E5000001 MBCustom ABL v2.4
    keymaster0x1140000001 MBKeymaster firmware
    misc0x12E4030001 MBBCB / boot control
    vbmeta0x14000000064 KB⚠️ AVB root — must disable before flashing modified images
    onyxconfig0x14400000032 MB⚠️ Onyx-proprietary — do not wipe
    userdata0x146000000~24 GBFDE encrypted (dm-2)

    E-ink Display

    • Driver: onyx_epdc_fb (built into kernel binary, not a module)
    • sysfs device: /sys/devices/sepdc
    • Framebuffer: /dev/graphics/fb0 (1872×1404, 32bpp RGBA)
    • EPDC control: /dev/ebc (char 10,35)
    • Waveform firmware: /waveform/eink_waveform.wbf (276 KB) — required at boot
    • Pipeline: MDSS DSI → TC358762 bridge → EPDC → MAX17135 PMIC

    Input Devices

    • Touch: cyttsp5 (MT type B, ABS_MT_POSITION_X range 0–1871, ABS_MT_POSITION_Y range 0–1403)
    • Pen: Wacom EMR digitizer (i2c@c1b6000/wacom@09)
    • Hall sensor: GPIO 105, south tile 0x03169004 (value 0 = cover closed)
    • Frontlight: LM3630A (i2c)
  • Research: Stock Recovery strace Analysis — Display Init & Input Map

    Research: Stock Recovery strace Analysis — Display Init & Input Map

    Stock Recovery strace Analysis

    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

    StepSyscallfdDetail
    1openat("/dev/graphics/fb0", O_RDWR|O_CLOEXEC)0Main fb0 handle
    2–3ioctl(FBIOGET_FSCREENINFO / VSCREENINFO)0Read screen params
    4mmap(21209088, MAP_SHARED)0Full double-buffer (7552×2808)
    5–8Open fb0 again → read geometry → close12ebc helper (geometry only)
    9openat("/dev/ebc", O_RDWR)12EPDC control device
    10mmap(10513152, MAP_SHARED)12ebc pixel buffer (7488×1404, pixel-exact)
    11ioctl(12, 0x700c) EBC_SEND_UPDATE12Init/clear — BEFORE blank
    12ioctl(0, FBIOBLANK, 4)0FB_BLANK_POWERDOWN
    13ioctl(0, FBIOBLANK, 0)0FB_BLANK_UNBLANK
    14–15ioctl(12, 0x700c) EBC_SEND_UPDATE ×212Content 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

    DeviceIdentityTWRP use
    event0Power + Back button (KEY_POWER, KEY_BACK)Use
    event1Capacitive touchscreen — MT type B (ABS_MT_SLOT, POSITION_X/Y, TRACKING_ID)Primary input
    event2EMR Wacom stylus (ABS_X/Y/PRESSURE/DISTANCE, BTN_TOOL_RUBBER/BRUSH)Blacklist
    event3USB/BT mouse (BTN_LEFT, BTN_RIGHT)Optional
    event4Virtual keys / GPIO (KEY_ENTER, KEY_HOME, KEY_UP…)Ignore
    event5Hall sensor (KEY_LEFTALT, KEY_POWER, KEY_WAKEUP)Blacklist
    event6Volume up (KEY_VOLUMEUP)Ignore

    Other Operations

    • Brightness: writes 127 to /sys/class/leds/lcd-backlight/brightness (LED class path, different from TWRP’s direct i2c path)
    • Zeros 2048 bytes of misc partition (clears BCB on every recovery boot)
    • Mounts /cache (ext4, /dev/block/mmcblk0p12)
    • Opens /dev/kmsg for dual logging
    • Spawns 3 threads: logging, property reader, screen update
  • R09–R11 — Medium Severity Risks

    R09 — Root Lost After Firmware Flash

    SeverityTriggerMitigation
    🟡 MediumFull OTA updateExpected behaviour — re-root using Phase 02 procedure

    R10 — Onyx Telemetry

    SeverityTriggerMitigation
    🟡 MediumUnblocked network on test deviceInstall AFWall+ immediately after rooting. Block all Onyx cloud services during development.

    R11 — GPL Compliance

    SeverityTriggerMitigation
    🟡 MediumPublishing firmware that contains Onyx kernel binaryDo 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.
  • R05–R08 — High Severity Risks

    R05 — Partition Size Mismatch

    FieldValue
    Severity🟠 High
    TriggerNA2 image larger than NA1 partition slot

    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

    FieldValue
    Severity🟠 High
    TriggerBooting 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

    FieldValue
    Severity🟠 High
    TriggerOTA 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

    FieldValue
    Severity🟠 High
    TriggerWrong 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.

  • R12 — ABL Crash → No 9008, Only Battery-Drain Recovery

    R12 — ABL Crash → No 9008 Without Battery Drain

    FieldValue
    Severity🔴 Critical
    IncidentABL 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
  • R02/R04 — EDL 900E Mode; Wrong Programmer

    R02 — EDL 900E Mode: No Recovery Loader

    FieldValue
    Severity🔴 Critical
    TriggerDevice fully unresponsive in 900E mode

    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

    FieldValue
    Severity🔴 Critical
    TriggerUsing 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.

  • R01 — Flash Wrong Bootloader (XBL/ABL from NA2)

    R01 — Flash Wrong Bootloader (XBL/ABL from NA2)

    FieldValue
    Severity🔴 Critical
    TriggerCopying NA2 xbl.elf/abl.elf onto NA1

    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.

  • Session 35 — 2026-03-30a — NA2 Firmware Acquired; SDM662 Discovery

    Session 35 — 2026-03-30a

    FieldValue
    Date2026-03-30
    Phase04 — Firmware Acquisition
    Duration~1 h

    Critical: NA2 Uses SDM662, Not SDM636

    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 1Note Air 2
    SoCSDM636 (sdm660)SDM662 (bengal)
    Kernel4.4.x4.19.157
    Android10 (SDK 29)11 (SDK 30)
    Partitionsstatic, single-slotdynamic A/B + super
    EncryptionFDEFBE

    Consequence: direct firmware port at partition level is not viable. Kernel, vendor HALs, and bootloaders are incompatible.

    NA2 Firmware Chain

    VersionTypeSizeURL MD5
    v4.0Full1.84 GB9bcffd50…
    v4.0.2Incremental50 MB91a889a3…
    v4.1.1Incremental338 MB04e3c7d5…

    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.

    Project Pivot

    1. APK extraction first — sideload NA2’s newer Onyx apps onto NA1’s Android 10
    2. GSI approach deferred — theoretically possible via Treble but VNDK mismatch risk (29 vs 30)
    3. Full partition port — definitively not viable
  • Session 33 — 2026-03-29d — ebc-probe Crashes Kernel; sysfs Readout Safe

    Session 33 — 2026-03-29d

    FieldValue
    Date2026-03-29
    Phase03b — TWRP (ebc-probe testing)
    Duration~30 min

    ebc-probe — Abandoned

    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):

    AttributeValue
    panel_initok
    waveform_versiononyx waveform sg
    wf_status99 (idle)
    epdc_active_luts[0x0][0x0][0x0][0x1] — 1 active LUT
    update_disable0 (updates enabled)
    frame counter245: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.

  • Session 32 — 2026-03-29c — Stock ABL RE: EDL Cable Detection Mechanism

    Session 32 — 2026-03-29c

    FieldValue
    Date2026-03-29
    Phase03b2 — Boot mode selection (EDL cable RE)
    Duration~3 h

    Stock ABL GetBootIntoMode — Reverse Engineered

    Found via "BootIntoDload detected. [%u ms]" string at file offset 0x3538f. Function GetBootIntoMode at VA 0x01bf8:

    1. Reads PMIC PON reason (logs cold_boot, PON1, KPDPWR, USB, DC flags)
    2. Polls proprietary Qualcomm protocol vtable at offset 0xf8 — 100 times in tight loop
    3. Value 8 = likely OCP (Other Charging Port) from PMIC APSD — what D+/GND short cable registers
    4. All 100 polls == 8 (first path) → BootIntoFastboot
    5. All 100 polls == 8 (second path) → BootIntoRecovery
    6. ≥50 polls == 8 (early exit) → BootIntoDload → EDL 9008

    Protocol GUID is in BSS (VA 0x53c08 — all zeros in binary, filled at runtime by XBL DXE drivers). Cannot be recovered statically.

    v2.5 — All Protocol Calls Hang from Fastboot

    Tested three protocol calls from fastboot oem detect-port — all hang the device:

    • EFI_USBFN_IO_PROTOCOL->DetectPort() — USB controller conflict
    • EFI_CHARGER_EX_PROTOCOL->GetChargerPresence() — charger hardware conflict
    • 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.