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