150 lines
7.9 KiB
Markdown
150 lines
7.9 KiB
Markdown
# mtk-wifi-fw (working name) — Project Plan
|
||
|
||
Goal: cut teeth on real firmware RE while producing community-useful tooling,
|
||
docs, and update tracking for MediaTek Connac2 WiFi firmware. The product is
|
||
the tooling/knowledge and the skills built making it — not a modified router.
|
||
|
||
## Target facts (verified, keep cited)
|
||
|
||
- Hardware: GL-MT3000 (Beryl AX), MT7981B (Filogic 820), OpenWrt 24.10.5.
|
||
Radios on-SoC at `platform/soc/18000000.wifi`, driver `mt7915e` (mt76).
|
||
- "The blob" = 4 images, 3 NDS32LE cores inside the SoC:
|
||
- `mt7981_wm.bin` 2.05MB — WM, main MAC/PHY MCU ("neptune", build 20240823)
|
||
- `mt7981_wa.bin` 494KB — WA, offload/stats MCU
|
||
- `mt7981_wo.bin` 2.45MB — WED packet offload core (FreeRTOS v10, loaded by
|
||
`mtk_wed`, not mt76 — separate container format, TODO)
|
||
- `mt7981_rom_patch.bin` 9.8KB — boot-ROM patch ("ALPS")
|
||
- NDS32LE evidence: `GCC: (2018-10-23_nds32le-elf-mculib-v3) 4.9.4` in wa;
|
||
`portable/GCC/NDS32/port.c` in wo.
|
||
- No signature/encryption wall: loader is the kernel driver
|
||
(`mt7915_load_firmware` → `mt76_connac2_load_patch` + `load_ram`); protocol
|
||
supports per-region encrypt (`FW_FEATURE_SET_ENCRYPT`) but blobs ship
|
||
plaintext. Source-verified; empirical proof = M3 milestone.
|
||
- Container formats (from `mt76_connac_mcu.h`):
|
||
- RAM images: region data from offset 0, n×40B region table, 36B trailer at
|
||
EOF. `fw_ver` stripped (`____000000`); build_date is the only versioning.
|
||
- Patch: 92B BE header + 64B BE section table at start.
|
||
- Family coverage: mt7915/7916/7981/7986 all parse. mt7915 blobs = 2022
|
||
build, others = 2024 — free pilot for version diffing.
|
||
- Tooling: Ghidra has an official NDS32 module (`NDS32:LE:32:default`, some
|
||
V3 instr gaps); Andes GNU toolchain public (exact 2018 GCC vintage exists).
|
||
- Prior art: cyrozap/mediatek-wifi-re (older chip gen; CC-BY-SA notes,
|
||
compatible). No public RE of Connac2-generation firmware exists.
|
||
|
||
## Strategy shape
|
||
|
||
RE first, fork later. Nobody can price replacement firmware before the boot
|
||
and core-boundary picture exists, so the plan front-loads cheap-certain RE and
|
||
gates expensive authoring behind a data-informed go/no-go.
|
||
|
||
- Phase 1 static RE: carve → ELF → Ghidra → boot/ABI map (no decision needed)
|
||
- Phase 2 dynamic RE: patch bytes, reload, observe (patching = verification
|
||
instrument, no decision needed)
|
||
- Fork point (after boot/handshake + WM↔WA boundary mapped): choose between
|
||
a) audit & document track, and/or
|
||
b) authoring ladder, easiest-first: custom WO (self-contained, no radio)
|
||
→ WM handshake-only → beacon TX → association → data path.
|
||
Each rung independently valuable/stoppable.
|
||
- Version diffing runs parallel throughout (pure static, high community value).
|
||
|
||
## MVP v0.1 — "toolkit + changelog" (no hardware required, ~8–12 evenings)
|
||
|
||
Scope: extract (family-wide, correct) + to-elf + diff report over
|
||
linux-firmware git history + format/boot docs + CI cron that tracks upstream
|
||
blob drops. The repo becomes the public changelog for silently-updated
|
||
firmware.
|
||
|
||
Worklist in order:
|
||
1. Repo scaffolding: git init, dirs, dual LICENSE (MIT code / CC-BY-SA
|
||
docs), Makefile; commit existing extractor.
|
||
2. Parser correctness: resolve or document-as-unknown the 100/36B gap,
|
||
region `type` semantics, feature bit 0x80.
|
||
3. Test fixtures: golden manifests per blob (metadata only, no blob bytes).
|
||
4. ELF emitter at true load addresses (Ghidra/objdump acceptance test).
|
||
5. Dataset: walk linux-firmware git history for mediatek WiFi files.
|
||
6. Diff engine + pilot report (mt7915 2022 vs 2024; string-table add/remove
|
||
is the human-readable signal).
|
||
7. Docs: format.md (every field cited), boot.md, README quickstart.
|
||
8. CI: fixtures on commit; weekly cron vs linux-firmware HEAD regenerating
|
||
reports.
|
||
9. Polish, tag v0.1.0, undersold announcement (OpenWrt forum + r/re).
|
||
|
||
Not in v0.1: Ghidra annotation projects, symbol DBs, patched blobs, anything
|
||
router-dependent.
|
||
|
||
## Quality gates ("not noise")
|
||
|
||
- Every claim cites evidence (kernel line, blob offset) or is marked unknown.
|
||
No invented semantics.
|
||
- Family coverage verified in CI, not asserted in README.
|
||
- Reproducible in ~3 commands, plain Linux, no blobs committed
|
||
(`make fetch-fw` pulls from kernel.org).
|
||
- Undersell announcements.
|
||
|
||
## Status log
|
||
|
||
- 2026-08-20: Extractor `tools/mtk_fw_extract.py` written and run on
|
||
mt7981/7915/7916/7986 wm+wa+patch (7 files, 4 chips) — all parse clean.
|
||
Output in `extracted*/`, `extracted/manifest.json`. Solved same day: the
|
||
"gap" is a second trailer family-wide (wm 100B, wa 36B) sitting between
|
||
region data and the kernel-parsed trailer; WM's carries the full build
|
||
string MTK strips from the kernel-visible trailer (branch, MP tag, build
|
||
timestamp) — recovered version metadata for the changelog. Region type:
|
||
all parsed blobs are FW_TYPE_DEFAULT(0); loader does use `type` elsewhere
|
||
(mt7921 FW_TYPE_CLC). Remaining unknowns: feature bit 0x80 (wm 0xf0xxxxxx
|
||
regions), hidden-trailer non-string fields. Verified claims + citations:
|
||
docs/findings.md.
|
||
- Router unreachable (thinkpad jump host down). Not blocking: v0.1 is pure
|
||
static. Hardware options when needed: fix thinkpad / wire devuan-hpz to
|
||
router LAN / join `zach` WiFi from devuan-hpz (key + likely MAC-whitelisted,
|
||
but changes this machine's network path mid-session).
|
||
|
||
- 2026-08-20 (later): MVP v0.1 complete. All 9 worklist steps: scaffold,
|
||
parser correctness (hidden trailer = recovered version metadata),
|
||
dataset-driven golden tests, ELF emitter (readelf-validated; Ghidra
|
||
open-check deferred to Ghidra bring-up — deviation noted), 54-revision
|
||
dataset, diff engine + 3 pilot reports (2026 build: 0xe003b000 region
|
||
~95% changed, new RA/DPD/thermal strings), docs (format/boot), CI
|
||
(push + weekly track), v0.1.0 tagged. Announcement drafted, not posted —
|
||
hosting decision still open.
|
||
|
||
- Repo name + hosting: RESOLVED — mtk-wifi-fw at
|
||
https://zachery.lol/code/zacheryasc/mtk-wifi-fw (self-hosted Forgejo 9,
|
||
public, pushed 2026-08-20 with v0.1.0). GitHub mirror optional later.
|
||
Forgejo Actions may pick up .github/workflows if a runner is registered
|
||
(ci-token exists on docean — unverified).
|
||
- Router access path (needed from M3/dynamic phase).
|
||
- Fork decision (audit vs authoring ladder mix) — after boot/boundary map.
|
||
- WO container format (from `mtk_wed_mcu.c`, different loader) — M2-ish.
|
||
|
||
## Decision function & finish criteria
|
||
|
||
Project has no natural completion point; finish = satisficing set + per-node
|
||
gates. All checks binary.
|
||
|
||
**Finish conditions (both required):**
|
||
- F1 public artifact: v0.1 shipped passing quality gates, then one of
|
||
community uptake / cron keeps it alive / documented sunset ("last verified
|
||
against linux-firmware X"). Silent rot is noise; sunset is finish.
|
||
- F2 teeth cut, each backed by an artifact: container parsed (done); one
|
||
*verified cited* claim from disassembly; changed firmware behavior and
|
||
observed it on hardware (P2); optionally self-written code on target.
|
||
|
||
**Universal gate (every checkpoint):** advance iff next gate is reachable
|
||
with known techniques AND has a stated cost ceiling AND its failure would not
|
||
invalidate shipped artifacts. Slipped >2x twice → stop-and-replan. Outputs
|
||
ship as verified or documented-unknown, never "probably"; unknowns are valid
|
||
P1 exits but never authoring foundations.
|
||
|
||
**Node exits:** MVP = worklist 1–9 + quality gates. P1 = boot chain writable
|
||
step-by-step with citations; ≥30 functions named via dispatch anchors, 3
|
||
traced end-to-end; memory map complete; WM↔WA characterized; fork memo.
|
||
Authoring rung N+1 opens iff rung N demonstrated on hardware AND N+1
|
||
interface mapped AND unbrick path proven.
|
||
|
||
**Kill criteria:** 3 consecutive flash cycles with no hypothesis advance →
|
||
rung closed, findings published. ROM-verified lockout discovered → authoring
|
||
dead, audit track unaffected. Router unreachable >4 weeks → P2 paused only.
|
||
|
||
**Zombie rule:** no commits and no CI activity for 2 quarters → archive with
|
||
last-verified statement.
|