Dataset-driven goldens: any tested blob must be a known linux-firmware revision (sha-keyed) matching recorded metadata; works for any snapshot; CI + fetch-fw target
This commit is contained in:
parent
cb00e3fd43
commit
844541e5a7
1 changed files with 52 additions and 47 deletions
|
|
@ -14,27 +14,29 @@ from pathlib import Path
|
||||||
REPO = Path(__file__).resolve().parent.parent
|
REPO = Path(__file__).resolve().parent.parent
|
||||||
FW = Path(os.environ.get('MTK_FW_DIR', '/lib/firmware/mediatek'))
|
FW = Path(os.environ.get('MTK_FW_DIR', '/lib/firmware/mediatek'))
|
||||||
|
|
||||||
# filename -> (chip_id, eco, n_region, hidden_trailer_string_or_None)
|
# Golden source of truth: dataset/history.jsonl (one record per
|
||||||
# Golden values observed from linux-firmware HEAD (2026-06-19 tree:
|
# linux-firmware revision, sha256-keyed). Any tested blob must be a known
|
||||||
# mt7981/mt7986 = 20260515 builds; mt7915/mt7916 = 2022/2024 builds,
|
# revision and its parse must match the recorded metadata. A new upstream
|
||||||
# unchanged since). When a value here fails against a newer snapshot, the
|
# build therefore fails here until the dataset is refreshed (by design):
|
||||||
# blob changed — update the golden *and* record the diff (docs/reports/).
|
#
|
||||||
GOLDEN_WM = {
|
# python3 tools/fw_history.py firmware/linux-firmware -o dataset/history.jsonl
|
||||||
'mt7981_wm.bin': (0x14, 0, 11,
|
import json
|
||||||
't-neptune-main-mt7915-1953-MT7981_MP2111_IMP-20260515121129'),
|
|
||||||
'mt7986_wm.bin': (0x0f, 0, 11,
|
HISTORY = json.loads(
|
||||||
't-neptune-main-mt7915-1953-MT7986_MP2111_IMP-20260515120228'),
|
'[' + ','.join(l for l in
|
||||||
'mt7916_wm.bin': (0x13, 0, 9,
|
(REPO / 'dataset' / 'history.jsonl').read_text().splitlines()
|
||||||
't-neptune-main-mt7915-1953-MT7916_MP2111_IMP-20240823170147'),
|
if l) + ']')
|
||||||
'mt7915_wm.bin': (0x0b, 1, 7,
|
BY_SHA = {r['sha256']: r for r in HISTORY}
|
||||||
't-neptune-mp-mt7915-2045-MT7915_MP_7_4_2045-20220929103802'),
|
|
||||||
}
|
|
||||||
GOLDEN_WA = {
|
def _expected(path: Path, sha: str):
|
||||||
'mt7981_wa.bin': (0x00, 0, 3, None),
|
rec = BY_SHA.get(sha)
|
||||||
'mt7986_wa.bin': (0x00, 0, 3, None),
|
if rec is None:
|
||||||
'mt7916_wa.bin': (0x00, 0, 3, None),
|
raise AssertionError(
|
||||||
'mt7915_wa.bin': (0x00, 1, 3, None),
|
f'{path.name}: sha {sha} is not a known linux-firmware revision '
|
||||||
}
|
f'in dataset/history.jsonl — refresh the dataset (see comment '
|
||||||
|
f'above) or verify the blob provenance')
|
||||||
|
return rec
|
||||||
|
|
||||||
|
|
||||||
def parse(path: Path, out: Path) -> dict:
|
def parse(path: Path, out: Path) -> dict:
|
||||||
|
|
@ -67,40 +69,43 @@ class LayoutClosure(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
class GoldenRAM(unittest.TestCase):
|
class GoldenRAM(unittest.TestCase):
|
||||||
|
"""Parsed metadata must match the dataset record for the blob's sha."""
|
||||||
|
|
||||||
def run_one(self, name, golden, outdir):
|
def test_ram(self):
|
||||||
p = FW / name
|
import hashlib
|
||||||
if not p.exists():
|
import sys as _sys
|
||||||
self.skipTest(f'{name} not present')
|
_sys.path.insert(0, str(REPO / 'tools'))
|
||||||
info = parse(p, outdir)
|
blobs = sorted(FW.glob('mt79*_wm.bin')) + sorted(FW.glob('mt79*_wa.bin'))
|
||||||
chip, eco, n, hidden = golden
|
if not blobs:
|
||||||
self.assertEqual(info['chip_id'], chip, name)
|
self.skipTest('no mediatek blobs on this host')
|
||||||
self.assertEqual(info['eco'], eco, name)
|
for p in blobs:
|
||||||
self.assertEqual(info['n_region'], n, name)
|
with self.subTest(blob=p.name):
|
||||||
ht = info.get('hidden_trailer', {})
|
d = p.read_bytes()
|
||||||
self.assertEqual(ht.get('string'), hidden, name)
|
rec = _expected(p, hashlib.sha256(d).hexdigest()[:16])
|
||||||
|
info = parse(p, REPO / 'extracted' / 'test_ram')
|
||||||
def test_wm(self):
|
self.assertEqual(info['chip_id'], rec.get('chip_id'), p.name)
|
||||||
for name, golden in GOLDEN_WM.items():
|
self.assertEqual(info['eco'], rec.get('eco'), p.name)
|
||||||
with self.subTest(blob=name):
|
self.assertEqual(info['n_region'], rec.get('n_region'), p.name)
|
||||||
self.run_one(name, golden, REPO / 'extracted' / 'test_wm')
|
self.assertEqual(info.get('hidden_trailer', {}).get('string'),
|
||||||
|
rec.get('hidden'), p.name)
|
||||||
def test_wa(self):
|
self.assertEqual(info['build_date'], rec.get('trailer_date'),
|
||||||
for name, golden in GOLDEN_WA.items():
|
p.name)
|
||||||
with self.subTest(blob=name):
|
|
||||||
self.run_one(name, golden, REPO / 'extracted' / 'test_wa')
|
|
||||||
|
|
||||||
|
|
||||||
class GoldenPatch(unittest.TestCase):
|
class GoldenPatch(unittest.TestCase):
|
||||||
|
|
||||||
def test_patch(self):
|
def test_patch(self):
|
||||||
golden = {'mt7981_rom_patch.bin': 1, 'mt7986_rom_patch.bin': 1,
|
import hashlib
|
||||||
'mt7916_rom_patch.bin': 1, 'mt7915_rom_patch.bin': 2}
|
blobs = sorted(FW.glob('mt79*_rom_patch.bin'))
|
||||||
for p in sorted(FW.glob('mt79*_rom_patch.bin')):
|
if not blobs:
|
||||||
|
self.skipTest('no mediatek blobs on this host')
|
||||||
|
for p in blobs:
|
||||||
with self.subTest(blob=p.name):
|
with self.subTest(blob=p.name):
|
||||||
|
d = p.read_bytes()
|
||||||
|
rec = _expected(p, hashlib.sha256(d).hexdigest()[:16])
|
||||||
info = parse(p, REPO / 'extracted' / 'test_patch')
|
info = parse(p, REPO / 'extracted' / 'test_patch')
|
||||||
self.assertEqual(info['platform'], 'ALPS')
|
self.assertEqual(info['platform'], rec.get('platform'), p.name)
|
||||||
self.assertEqual(info['n_region'], golden[p.name])
|
self.assertEqual(info['n_region'], rec.get('n_section'), p.name)
|
||||||
for sec in info['sections']:
|
for sec in info['sections']:
|
||||||
self.assertEqual(sec['type'], '0x30002')
|
self.assertEqual(sec['type'], '0x30002')
|
||||||
self.assertEqual(sec['enc_type'], 0) # plaintext (F4)
|
self.assertEqual(sec['enc_type'], 0) # plaintext (F4)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue