1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
"""PMC / master register block (first-touch device).
Evidence kind: **hardware register/field header + firmware use + observed
access pattern.**
* ``NV_PMC_BOOT_42`` lives at offset ``0xA00`` of the master (PMC) block and is
read by the GSP boot code through the PRIV window at
``0x2000_0000_0000_0A00`` (observed 4-byte read, first MMIO of the real
570.144 image; the QEMU baseline faults there).
* The firmware extracts bits ``28:20`` (``NV_PMC_BOOT_42_CHIP_ID``) and
compares against the TU10x IDs ``0x162..0x168``; only a match continues the
boot (observed branch chain at firmware vaddr ``0x4009020``).
* ``NV_PMC_BOOT_42`` field layout: ARCHITECTURE ``28:24`` (TU100 = ``0x16``),
IMPLEMENTATION ``23:20``, MAJOR_REVISION ``19:16``, MINOR_REVISION
``15:12``, MINOR_EXTENDED_REVISION ``11:8``, CHIP_ID ``28:20``.
Only ``0xA00`` is modelled; every other offset in the window stays unhandled
and is logged by the machine.
"""
from __future__ import annotations
from .base import Device
BOOT_42_OFFSET = 0xA00
CHIP_ID_SHIFT = 20
CHIP_ID_MASK = 0x1FF
ARCHITECTURE_MASK = 0x1F
IMPLEMENTATION_MASK = 0xF
MAJOR_MASK = 0xF
MINOR_MASK = 0xF
MINOR_EXT_MASK = 0xF
#: Chip IDs seen in the firmware's comparison chain (header field values).
#: TU105 (0x165) is kept because it appears in the observed chain, but its
#: product mapping is unverified. The former ``TU107 = 0x167`` entry was a
#: transcription error (0x167 is TU117) and has been removed.
TU102 = 0x162
TU104 = 0x164
TU105 = 0x165 # unverified product mapping (observed in the chain only)
TU106 = 0x166
TU116 = 0x168
TU117 = 0x167
def boot_42_value(chip_id: int, *, major: int = 0, minor: int = 0,
minor_ext: int = 0) -> int:
"""Assemble an ``NV_PMC_BOOT_42`` value from its documented fields.
ARCHITECTURE and IMPLEMENTATION are derived from ``chip_id`` (they are the
upper/lower nibbles of the same bits ``28:20``), matching the header's
``CHIP_ID_TU104 = 0x164`` / ``ARCHITECTURE_TU100 = 0x16`` pair.
"""
chip_id &= CHIP_ID_MASK
arch = (chip_id >> 4) & ARCHITECTURE_MASK
impl = chip_id & IMPLEMENTATION_MASK
value = (chip_id << CHIP_ID_SHIFT)
value |= (arch << 24) | (impl << 20)
value |= (major & MAJOR_MASK) << 16
value |= (minor & MINOR_MASK) << 12
value |= (minor_ext & MINOR_EXT_MASK) << 8
return value
class PmcBlock(Device):
"""Master/PMC block: ``NV_PMC_BOOT_42`` chip identification."""
name = "pmc"
def __init__(self, *, chip_id: int = TU104, major: int = 0, minor: int = 0,
minor_ext: int = 0, boot_42: int | None = None,
base: int = 0, size: int = 0x1000):
super().__init__(base=base, size=size)
self.chip_id = chip_id
self.boot_42 = boot_42 if boot_42 is not None else boot_42_value(
chip_id, major=major, minor=minor, minor_ext=minor_ext)
def read(self, offset: int, size: int) -> int | None:
if offset == BOOT_42_OFFSET and size == 4:
return self.boot_42
return None
def peek(self, offset: int, size: int) -> int | None:
return self.read(offset, size)
def write(self, offset: int, size: int, value: int) -> bool:
# NV_PMC_BOOT_42 is read-only (R--4R).
return False
def state(self) -> dict:
return {"chip_id": self.chip_id, "boot_42": self.boot_42}
|