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