mtk-wifi-fw/docs/format.md

98 lines
4.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MediaTek Connac2 WiFi firmware container format
Scope: `mt7915/7916/7981/7986_{wm,wa,rom_patch}.bin` as shipped in
linux-firmware. All field layouts are transcribed from
`drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h` (structs
`mt76_connac2_fw_trailer`, `mt76_connac2_fw_region`,
`mt76_connac2_patch_hdr`, `mt76_connac2_patch_sec`); loader behavior from
`mt76_connac_mcu.c` (`mt76_connac2_load_patch`, `mt76_connac2_load_ram`,
`mt76_connac2_send_ram`). Verified against 54 historical blob revisions
(`dataset/history.jsonl`).
## RAM images (`*_wm.bin`, `*_wa.bin`) — little-endian
```
offset 0: region data, packed back-to-back in region-table order
(driver streams from offset 0, advancing by each region's len)
+sum(len): [optional] hidden second trailer — 100B on WM, 36B on WA
(present on every observed revision; loader never reads it)
+gap: region table: n_region × 40-byte records
end-36: 36-byte trailer
```
### Region record (40 bytes)
| off | size | field | notes |
|---|---|---|---|
| 0 | 4 | decomp_crc | CRC of decompressed data (unused when decomp_len==0) |
| 4 | 4 | decomp_len | 0 = stored uncompressed (all observed revisions) |
| 8 | 4 | decomp_blk_sz | MCU-side decompression block size |
| 12 | 4 | rsv | |
| 16 | 4 | addr | download destination (bus address) |
| 20 | 4 | len | stored length == download length |
| 24 | 1 | feature_set | bit0 ENCRYPT, bits1-2 KEY_IDX, bit4 ENCRY_MODE, bit5 OVERRIDE_ADDR, bit6 NON_DL, **bit7: undefined upstream — see U1** |
| 25 | 1 | type | content tag: 0 DEFAULT everywhere in this family; mt7921 uses 2 = CLC (country/location data, paired with NON_DL) |
| 26 | 14 | rsv1 | |
Observed `feature_set` bits in the wild: `0x20` (OVERRIDE_ADDR, WM region 0),
`0x80` (unknown, all `0xf0xxxxxx` regions), `0xc0` (NON_DL|0x80, zero-length
entries). No observed blob sets ENCRYPT.
### Trailer (36 bytes, at EOF)
| off | size | field | notes |
|---|---|---|---|
| 0 | 1 | chip_id | 0x0b mt7915, 0x13 mt7916, 0x14 mt7981, 0x0f mt7986 (WM); 0x00 on WA |
| 1 | 1 | eco_code | silicon eco |
| 2 | 1 | n_region | |
| 3 | 1 | format_ver | |
| 4 | 1 | format_flag | |
| 5 | 2 | rsv | |
| 6 | 10 | fw_ver[10] | **stripped by MTK**: `____000000` (WM) / `DEV_000000` (WA) |
| 16 | 15 | build_date[15] | `%Y%m%d%H%M%S` ASCII |
| 31 | 4 | crc | LE32 |
### Hidden second trailer (not read by the upstream loader)
WM (100B): `16×'#'`, `40 00 00 00`, 1-byte string length, flags, then the
full build string `t-neptune-<branch>-mt7915-<n>-<CHIP>_<MPTAG>_<MPVER>-<build-ts>`,
`'#'`-padded. WA (36B): no string. This restores the version metadata MTK
strips from fw_ver — the key input to version diffing (`tools/fw_history.py`).
Observed build strings per revision: `dataset/history.jsonl`.
## Patch images (`*_rom_patch.bin`) — big-endian
```
offset 0: 92-byte header
offset 92: n_section × 64-byte section records
explicit: section data at each section's `offs`
```
Header: `build_date[16]`, `platform[4]` ("ALPS" on all observed), `hw_sw_ver`,
`patch_ver`, `checksum(u16)`, `rsv(u16)`, descriptor (`patch_ver`, `subsys`,
`feature`, `n_section`, `crc`, `rsv[11]`).
Section record: `type`, `offs`, `size`, info union (`addr`, `len`,
`key_idx`/enc-mode, `align_len`). Observed: `type == 0x30002` on every
section; `enc_type == 0` (plaintext); download addresses `0x00900000`-range;
section counts 1 (7916/7981/7986) and 2 (7915, one small + one data section).
## WO images (`mt7981_wo.bin`, `mt7986_wo_{0,1}.bin`)
Different container, loaded by the ethernet-side WED driver
(`drivers/net/ethernet/mediatek/mtk_wed_mcu.c`), not mt76. Not yet parsed
(unknown U3). Firmware content: FreeRTOS v10.0 + NDS32 port, "coe/" source
paths (string evidence).
## Firmware ISA
NDS32 (Andes) 32-bit little-endian. Evidence: `GCC: (2018-10-23_nds32le-elf-mculib-v3) 4.9.4` in mt7981_wa data;
`portable/GCC/NDS32/port.c` in mt7981_wo. `tools/mtk_fw_elf.py` emits
`EM_NDS32`(167) ET_EXEC ELF for Ghidra import.
## Unknowns
U1 `feature_set` bit7 (0x80): correlated with `0xf0xxxxxx` destinations;
undefined upstream. U2 hidden-trailer non-string fields. U3 WO container
format. See `docs/findings.md`.