xref: /linux/drivers/gpu/nova-core/firmware/tlv.rs (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1*33f40117STimur Tabi // SPDX-License-Identifier: GPL-2.0
2*33f40117STimur Tabi // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3*33f40117STimur Tabi 
4*33f40117STimur Tabi use kernel::{
5*33f40117STimur Tabi     device,
6*33f40117STimur Tabi     firmware,
7*33f40117STimur Tabi     prelude::*,
8*33f40117STimur Tabi     str::CString, //
9*33f40117STimur Tabi };
10*33f40117STimur Tabi 
11*33f40117STimur Tabi use crate::{
12*33f40117STimur Tabi     gpu,
13*33f40117STimur Tabi     num::*, //
14*33f40117STimur Tabi };
15*33f40117STimur Tabi 
16*33f40117STimur Tabi /// Requests the GPU firmware TLV `name` suitable for `chipset`.
17*33f40117STimur Tabi pub(crate) fn request_tlv(
18*33f40117STimur Tabi     dev: &device::Device,
19*33f40117STimur Tabi     chipset: gpu::Chipset,
20*33f40117STimur Tabi     name: &str,
21*33f40117STimur Tabi ) -> Result<firmware::Firmware> {
22*33f40117STimur Tabi     let chip_name = chipset.name();
23*33f40117STimur Tabi 
24*33f40117STimur Tabi     let filename = CString::try_from_fmt(fmt!("nvidia/{chip_name}/gsp/{name}.tlv"))?;
25*33f40117STimur Tabi 
26*33f40117STimur Tabi     dev_dbg!(dev, "loading firmware image {:?}\n", &filename);
27*33f40117STimur Tabi 
28*33f40117STimur Tabi     firmware::Firmware::request(&filename, dev)
29*33f40117STimur Tabi }
30*33f40117STimur Tabi 
31*33f40117STimur Tabi struct TlvBlock<'a> {
32*33f40117STimur Tabi     tag: [u8; 4],
33*33f40117STimur Tabi     value: &'a [u8],
34*33f40117STimur Tabi }
35*33f40117STimur Tabi 
36*33f40117STimur Tabi /// On-wire TLV block header: 4-byte ASCII tag + little-endian payload length (bytes, excluding
37*33f40117STimur Tabi /// padding to a 4-byte boundary).
38*33f40117STimur Tabi struct TlvBlockHeader {
39*33f40117STimur Tabi     tag: [u8; 4],
40*33f40117STimur Tabi     length: usize,
41*33f40117STimur Tabi }
42*33f40117STimur Tabi 
43*33f40117STimur Tabi impl TlvBlockHeader {
44*33f40117STimur Tabi     const SIZE: usize = size_of::<[u8; 4]>() + size_of::<u32>();
45*33f40117STimur Tabi 
46*33f40117STimur Tabi     /// Parses the first [`Self::SIZE`] bytes of `hdr` (caller may pass a longer slice).
47*33f40117STimur Tabi     fn parse(hdr: &[u8]) -> Option<Self> {
48*33f40117STimur Tabi         let hdr = hdr.get(..Self::SIZE)?;
49*33f40117STimur Tabi         let tag = <[u8; 4]>::try_from(hdr.get(..4)?).ok()?;
50*33f40117STimur Tabi         if !tag.is_ascii() {
51*33f40117STimur Tabi             return None;
52*33f40117STimur Tabi         }
53*33f40117STimur Tabi         let len_arr = <[u8; 4]>::try_from(hdr.get(4..Self::SIZE)?).ok()?;
54*33f40117STimur Tabi         let length = u32_as_usize(u32::from_le_bytes(len_arr));
55*33f40117STimur Tabi         Some(Self { tag, length })
56*33f40117STimur Tabi     }
57*33f40117STimur Tabi }
58*33f40117STimur Tabi 
59*33f40117STimur Tabi /// Iterator over the [`TlvBlock`]s of a [`Tlv`].
60*33f40117STimur Tabi ///
61*33f40117STimur Tabi /// # Invariants
62*33f40117STimur Tabi ///
63*33f40117STimur Tabi /// `pos` is a byte offset into `tlv.data` that always lies on a block boundary (in the sense
64*33f40117STimur Tabi /// of the [`Tlv`] invariant): it is either the start of a well-formed block, or equal to
65*33f40117STimur Tabi /// `tlv.data.len()` (end of iteration).
66*33f40117STimur Tabi struct TlvIter<'tlv, 'a> {
67*33f40117STimur Tabi     tlv: &'tlv Tlv<'a>,
68*33f40117STimur Tabi     pos: usize,
69*33f40117STimur Tabi }
70*33f40117STimur Tabi 
71*33f40117STimur Tabi impl<'tlv, 'a> Iterator for TlvIter<'tlv, 'a> {
72*33f40117STimur Tabi     type Item = TlvBlock<'a>;
73*33f40117STimur Tabi 
74*33f40117STimur Tabi     /// Returns the block starting at `self.pos` and advances the cursor past it, or [`None`]
75*33f40117STimur Tabi     /// once the cursor reaches the end of the data or encounters an error.
76*33f40117STimur Tabi     ///
77*33f40117STimur Tabi     /// Note that errors cannot actually occur because the data is validated in the constructor.
78*33f40117STimur Tabi     fn next(&mut self) -> Option<Self::Item> {
79*33f40117STimur Tabi         if self.pos >= self.tlv.data.len() {
80*33f40117STimur Tabi             return None;
81*33f40117STimur Tabi         }
82*33f40117STimur Tabi 
83*33f40117STimur Tabi         let tail = self.tlv.data.get(self.pos..)?;
84*33f40117STimur Tabi 
85*33f40117STimur Tabi         let hdr = tail.get(..TlvBlockHeader::SIZE)?;
86*33f40117STimur Tabi         let header = TlvBlockHeader::parse(hdr)?;
87*33f40117STimur Tabi 
88*33f40117STimur Tabi         let stored_size = header.length.checked_next_multiple_of(4)?;
89*33f40117STimur Tabi         let advance = TlvBlockHeader::SIZE.checked_add(stored_size)?;
90*33f40117STimur Tabi         let payload_end = TlvBlockHeader::SIZE.checked_add(header.length)?;
91*33f40117STimur Tabi 
92*33f40117STimur Tabi         let value = tail
93*33f40117STimur Tabi             .get(..advance)?
94*33f40117STimur Tabi             .get(TlvBlockHeader::SIZE..payload_end)?;
95*33f40117STimur Tabi 
96*33f40117STimur Tabi         // INVARIANT: by the `Tlv` invariant the block at `self.pos` occupies exactly `advance`
97*33f40117STimur Tabi         // bytes, so `self.pos + advance` is the next block boundary (or `data.len()`).
98*33f40117STimur Tabi         self.pos = self.pos.checked_add(advance)?;
99*33f40117STimur Tabi 
100*33f40117STimur Tabi         Some(TlvBlock {
101*33f40117STimur Tabi             tag: header.tag,
102*33f40117STimur Tabi             value,
103*33f40117STimur Tabi         })
104*33f40117STimur Tabi     }
105*33f40117STimur Tabi }
106*33f40117STimur Tabi 
107*33f40117STimur Tabi /// The post-header part of a validated TLV (type, length, value) firmware image.
108*33f40117STimur Tabi ///
109*33f40117STimur Tabi /// TLV firmware images start with a 4-byte "NVFW" magic header, followed by a sequence of
110*33f40117STimur Tabi /// blocks. Each block has a 4-byte type tag, a 4-byte length field, and a data payload
111*33f40117STimur Tabi /// (value) whose stored size is the length rounded up to the nearest multiple of 4.
112*33f40117STimur Tabi ///
113*33f40117STimur Tabi /// [`Self::new`] checks the magic header and walks every block: tags must be ASCII,
114*33f40117STimur Tabi /// lengths and padding must fit without overflow, and the byte stream after `NVFW` must
115*33f40117STimur Tabi /// be exactly partitionable into blocks (no trailing partial header or slack). After
116*33f40117STimur Tabi /// that, [`TlvIter`] only signals end-of-stream via [`None`], not parse failure.
117*33f40117STimur Tabi ///
118*33f40117STimur Tabi /// Although the spec forbids duplicate tags, neither the constructor nor the iterator
119*33f40117STimur Tabi /// enforces this restriction.  Instead, duplicate tags are simply ignored.
120*33f40117STimur Tabi ///
121*33f40117STimur Tabi /// # Invariants
122*33f40117STimur Tabi ///
123*33f40117STimur Tabi /// `data` is a validated TLV payload (the bytes *after* the `NVFW` magic): it is the exact
124*33f40117STimur Tabi /// concatenation of zero or more well-formed blocks, with no trailing partial header or slack.
125*33f40117STimur Tabi /// Consequently, any offset `o` into `data` that is a block boundary and satisfies
126*33f40117STimur Tabi /// `o < data.len()` is the start of a complete block whose header parses and whose stored
127*33f40117STimur Tabi /// extent (`TlvBlockHeader::SIZE + header.length.next_multiple_of(4)` bytes) lies within
128*33f40117STimur Tabi /// `data`. `data.len()` is itself a boundary.
129*33f40117STimur Tabi pub(crate) struct Tlv<'a> {
130*33f40117STimur Tabi     data: &'a [u8],
131*33f40117STimur Tabi }
132*33f40117STimur Tabi 
133*33f40117STimur Tabi impl<'a> Tlv<'a> {
134*33f40117STimur Tabi     const MAGIC: &'static [u8; 4] = b"NVFW";
135*33f40117STimur Tabi 
136*33f40117STimur Tabi     /// Parses `data` as a TLV firmware image, returning [`EINVAL`] if the image is malformed.
137*33f40117STimur Tabi     pub(crate) fn new(data: &'a [u8]) -> Result<Self> {
138*33f40117STimur Tabi         // Verify that the magic bytes exist and are the correct value
139*33f40117STimur Tabi         let magic_len = Self::MAGIC.len();
140*33f40117STimur Tabi         if data
141*33f40117STimur Tabi             .get(..magic_len)
142*33f40117STimur Tabi             .is_none_or(|magic| magic != Self::MAGIC)
143*33f40117STimur Tabi         {
144*33f40117STimur Tabi             return Err(EINVAL);
145*33f40117STimur Tabi         }
146*33f40117STimur Tabi 
147*33f40117STimur Tabi         // The payload is the contiguous sequence of TLV blocks after the magic.
148*33f40117STimur Tabi         let payload = data.get(magic_len..).ok_or(EINVAL)?;
149*33f40117STimur Tabi 
150*33f40117STimur Tabi         // The spec says every TLV must have a VERS tag.
151*33f40117STimur Tabi         let mut has_vers = false;
152*33f40117STimur Tabi 
153*33f40117STimur Tabi         let mut rest = payload;
154*33f40117STimur Tabi         while !rest.is_empty() {
155*33f40117STimur Tabi             // Validate and extract the header (type, length).
156*33f40117STimur Tabi             let Some(header): Option<TlvBlockHeader> = rest
157*33f40117STimur Tabi                 .get(..TlvBlockHeader::SIZE)
158*33f40117STimur Tabi                 .and_then(TlvBlockHeader::parse)
159*33f40117STimur Tabi             else {
160*33f40117STimur Tabi                 return Err(EINVAL);
161*33f40117STimur Tabi             };
162*33f40117STimur Tabi 
163*33f40117STimur Tabi             has_vers |= header.tag == *b"VERS";
164*33f40117STimur Tabi 
165*33f40117STimur Tabi             // The `length` field of a TLV block contains the actual byte length of the
166*33f40117STimur Tabi             // value, but each TLV block is aligned to a 4-byte boundary.
167*33f40117STimur Tabi             let Some(stored_size) = header.length.checked_next_multiple_of(4) else {
168*33f40117STimur Tabi                 return Err(EINVAL);
169*33f40117STimur Tabi             };
170*33f40117STimur Tabi 
171*33f40117STimur Tabi             let length = TlvBlockHeader::SIZE
172*33f40117STimur Tabi                 .checked_add(stored_size)
173*33f40117STimur Tabi                 .ok_or(EINVAL)?;
174*33f40117STimur Tabi 
175*33f40117STimur Tabi             rest = rest.split_at_checked(length).ok_or(EINVAL)?.1;
176*33f40117STimur Tabi         }
177*33f40117STimur Tabi 
178*33f40117STimur Tabi         if !has_vers {
179*33f40117STimur Tabi             return Err(EINVAL);
180*33f40117STimur Tabi         }
181*33f40117STimur Tabi 
182*33f40117STimur Tabi         // INVARIANT: the loop above walked `payload` block-by-block. For each block, the
183*33f40117STimur Tabi         // header is parsed (`TlvBlockHeader::parse` rejects non-ASCII tags), and the
184*33f40117STimur Tabi         // stored extent (`SIZE + length.next_multiple_of(4)`) is computed without
185*33f40117STimur Tabi         // overflow and split off `rest` only when it fits. The loop ends only when `rest`
186*33f40117STimur Tabi         // is empty, so the byte stream is an exact concatenation of blocks with no
187*33f40117STimur Tabi         // trailing partial header or slack.
188*33f40117STimur Tabi         Ok(Self { data: payload })
189*33f40117STimur Tabi     }
190*33f40117STimur Tabi 
191*33f40117STimur Tabi     fn iter(&self) -> TlvIter<'_, 'a> {
192*33f40117STimur Tabi         // INVARIANT: 0 is a block boundary, either the start of the first block,
193*33f40117STimur Tabi         // or `data.len()` when `data` is empty.
194*33f40117STimur Tabi         TlvIter { tlv: self, pos: 0 }
195*33f40117STimur Tabi     }
196*33f40117STimur Tabi 
197*33f40117STimur Tabi     fn find(&self, tag: &[u8; 4]) -> Result<TlvBlock<'a>> {
198*33f40117STimur Tabi         self.iter().find(|b| b.tag == *tag).ok_or(EINVAL)
199*33f40117STimur Tabi     }
200*33f40117STimur Tabi 
201*33f40117STimur Tabi     /// Return a slice of bytes.
202*33f40117STimur Tabi     ///
203*33f40117STimur Tabi     /// Returns `EINVAL` if the value is empty.
204*33f40117STimur Tabi     pub(crate) fn get_bytes(&self, tag: &[u8; 4]) -> Result<&'a [u8]> {
205*33f40117STimur Tabi         let tlv = self.find(tag)?;
206*33f40117STimur Tabi 
207*33f40117STimur Tabi         // Treat empty value as an error, to avoid trying to parse nothing.
208*33f40117STimur Tabi         if tlv.value.is_empty() {
209*33f40117STimur Tabi             return Err(EINVAL); // TODO: Use ENODATA once available.
210*33f40117STimur Tabi         }
211*33f40117STimur Tabi 
212*33f40117STimur Tabi         Ok(tlv.value)
213*33f40117STimur Tabi     }
214*33f40117STimur Tabi 
215*33f40117STimur Tabi     /// Return a little-endian u32.
216*33f40117STimur Tabi     pub(crate) fn get_u32(&self, tag: &[u8; 4]) -> Result<u32> {
217*33f40117STimur Tabi         let tlv = self.find(tag)?;
218*33f40117STimur Tabi 
219*33f40117STimur Tabi         tlv.value
220*33f40117STimur Tabi             .try_into()
221*33f40117STimur Tabi             .ok()
222*33f40117STimur Tabi             .map(u32::from_le_bytes)
223*33f40117STimur Tabi             .ok_or(EINVAL)
224*33f40117STimur Tabi     }
225*33f40117STimur Tabi 
226*33f40117STimur Tabi     /// Return a string value.
227*33f40117STimur Tabi     pub(crate) fn get_string(&self, tag: &[u8; 4]) -> Result<&'a str> {
228*33f40117STimur Tabi         let tlv = self.find(tag)?;
229*33f40117STimur Tabi 
230*33f40117STimur Tabi         let bytes = tlv.value;
231*33f40117STimur Tabi 
232*33f40117STimur Tabi         // Strings can only contain printable ASCII characters.
233*33f40117STimur Tabi         if bytes.iter().any(|&b| !(32..127).contains(&b)) {
234*33f40117STimur Tabi             return Err(EINVAL);
235*33f40117STimur Tabi         }
236*33f40117STimur Tabi 
237*33f40117STimur Tabi         core::str::from_utf8(bytes).map_err(|_| EINVAL)
238*33f40117STimur Tabi     }
239*33f40117STimur Tabi 
240*33f40117STimur Tabi     /// Obtain the nth signature from a SIGN tag.  If `index` is None,
241*33f40117STimur Tabi     /// then return the last signature.
242*33f40117STimur Tabi     pub(crate) fn get_signature(&self, index: Option<usize>) -> Result<&'a [u8]> {
243*33f40117STimur Tabi         let num_sigs: usize = match self.get_u32(b"NSIG")? {
244*33f40117STimur Tabi             0 => return Err(EINVAL),
245*33f40117STimur Tabi             n => n.into_safe_cast(),
246*33f40117STimur Tabi         };
247*33f40117STimur Tabi 
248*33f40117STimur Tabi         let sig_bytes = self.get_bytes(b"SIGN")?;
249*33f40117STimur Tabi 
250*33f40117STimur Tabi         // Ensure that sig_bytes can be divided evenly into chunks.
251*33f40117STimur Tabi         if sig_bytes.len() % num_sigs != 0 {
252*33f40117STimur Tabi             return Err(EINVAL);
253*33f40117STimur Tabi         }
254*33f40117STimur Tabi 
255*33f40117STimur Tabi         // num_sigs cannot be 0, and sig_bytes cannot be empty, so this cannot panic.
256*33f40117STimur Tabi         let sig_size = sig_bytes.len() / num_sigs;
257*33f40117STimur Tabi 
258*33f40117STimur Tabi         let index = index.unwrap_or(num_sigs - 1);
259*33f40117STimur Tabi 
260*33f40117STimur Tabi         sig_bytes.chunks_exact(sig_size).nth(index).ok_or(EINVAL)
261*33f40117STimur Tabi     }
262*33f40117STimur Tabi }
263