1 // SPDX-License-Identifier: GPL-2.0 2 // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 4 //! Contains structures and functions dedicated to the parsing, building and patching of firmwares 5 //! to be loaded into a given execution unit. 6 7 use core::marker::PhantomData; 8 use core::ops::Deref; 9 10 use kernel::{ 11 firmware, 12 prelude::*, // 13 }; 14 15 use crate::{ 16 falcon::{ 17 FalconDmaLoadTarget, 18 FalconFirmware, // 19 }, 20 gpu, 21 gsp::boot_firmware_files, 22 num::IntoSafeCast, // 23 }; 24 25 pub(crate) mod booter; 26 pub(crate) mod fsp; 27 pub(crate) mod fwsec; 28 pub(crate) mod gsp; 29 pub(crate) mod riscv; 30 pub(crate) mod tlv; 31 32 /// Structure used to describe some firmwares, notably FWSEC-FRTS. 33 #[repr(C)] 34 #[derive(Debug, Clone, FromBytes)] 35 pub(crate) struct FalconUCodeDescV2 { 36 /// Header defined by 'NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC*' in OpenRM. 37 hdr: u32, 38 /// Stored size of the ucode after the header, compressed or uncompressed 39 stored_size: u32, 40 /// Uncompressed size of the ucode. If store_size == uncompressed_size, then the ucode 41 /// is not compressed. 42 pub(crate) uncompressed_size: u32, 43 /// Code entry point 44 pub(crate) virtual_entry: u32, 45 /// Offset after the code segment at which the Application Interface Table headers are located. 46 pub(crate) interface_offset: u32, 47 /// Base address at which to load the code segment into 'IMEM'. 48 pub(crate) imem_phys_base: u32, 49 /// Size in bytes of the code to copy into 'IMEM' (includes both secure and non-secure 50 /// segments). 51 pub(crate) imem_load_size: u32, 52 /// Virtual 'IMEM' address (i.e. 'tag') at which the code should start. 53 pub(crate) imem_virt_base: u32, 54 /// Virtual address of secure IMEM segment. 55 pub(crate) imem_sec_base: u32, 56 /// Size of secure IMEM segment. 57 pub(crate) imem_sec_size: u32, 58 /// Offset into stored (uncompressed) image at which DMEM begins. 59 pub(crate) dmem_offset: u32, 60 /// Base address at which to load the data segment into 'DMEM'. 61 pub(crate) dmem_phys_base: u32, 62 /// Size in bytes of the data to copy into 'DMEM'. 63 pub(crate) dmem_load_size: u32, 64 /// "Alternate" Size of data to load into IMEM. 65 pub(crate) alt_imem_load_size: u32, 66 /// "Alternate" Size of data to load into DMEM. 67 pub(crate) alt_dmem_load_size: u32, 68 } 69 70 /// Structure used to describe some firmwares, notably FWSEC-FRTS. 71 #[repr(C)] 72 #[derive(Debug, Clone, FromBytes)] 73 pub(crate) struct FalconUCodeDescV3 { 74 /// Header defined by `NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC*` in OpenRM. 75 hdr: u32, 76 /// Stored size of the ucode after the header. 77 stored_size: u32, 78 /// Offset in `DMEM` at which the signature is expected to be found. 79 pub(crate) pkc_data_offset: u32, 80 /// Offset after the code segment at which the app headers are located. 81 pub(crate) interface_offset: u32, 82 /// Base address at which to load the code segment into `IMEM`. 83 pub(crate) imem_phys_base: u32, 84 /// Size in bytes of the code to copy into `IMEM`. 85 pub(crate) imem_load_size: u32, 86 /// Virtual `IMEM` address (i.e. `tag`) at which the code should start. 87 pub(crate) imem_virt_base: u32, 88 /// Base address at which to load the data segment into `DMEM`. 89 pub(crate) dmem_phys_base: u32, 90 /// Size in bytes of the data to copy into `DMEM`. 91 pub(crate) dmem_load_size: u32, 92 /// Mask of the falcon engines on which this firmware can run. 93 pub(crate) engine_id_mask: u16, 94 /// ID of the ucode used to infer a fuse register to validate the signature. 95 pub(crate) ucode_id: u8, 96 /// Number of signatures in this firmware. 97 pub(crate) signature_count: u8, 98 /// Versions of the signatures, used to infer a valid signature to use. 99 pub(crate) signature_versions: u16, 100 _reserved: u16, 101 } 102 103 /// Enum wrapping the different versions of Falcon microcode descriptors. 104 /// 105 /// This allows handling both V2 and V3 descriptor formats through a 106 /// unified type, providing version-agnostic access to firmware metadata 107 /// via the [`FalconUCodeDescriptor`] trait. 108 #[derive(Debug, Clone)] 109 pub(crate) enum FalconUCodeDesc { 110 V2(FalconUCodeDescV2), 111 V3(FalconUCodeDescV3), 112 } 113 114 impl Deref for FalconUCodeDesc { 115 type Target = dyn FalconUCodeDescriptor; 116 117 fn deref(&self) -> &Self::Target { 118 match self { 119 FalconUCodeDesc::V2(v2) => v2, 120 FalconUCodeDesc::V3(v3) => v3, 121 } 122 } 123 } 124 125 /// Trait providing a common interface for accessing Falcon microcode descriptor fields. 126 /// 127 /// This trait abstracts over the different descriptor versions ([`FalconUCodeDescV2`] and 128 /// [`FalconUCodeDescV3`]), allowing code to work with firmware metadata without needing to 129 /// know the specific descriptor version. Fields not present return zero. 130 pub(crate) trait FalconUCodeDescriptor { 131 fn hdr(&self) -> u32; 132 fn imem_load_size(&self) -> u32; 133 fn interface_offset(&self) -> u32; 134 fn dmem_load_size(&self) -> u32; 135 fn pkc_data_offset(&self) -> u32; 136 fn engine_id_mask(&self) -> u16; 137 fn ucode_id(&self) -> u8; 138 fn signature_count(&self) -> u8; 139 fn signature_versions(&self) -> u16; 140 141 /// Returns the size in bytes of the header. 142 fn size(&self) -> usize { 143 let hdr = self.hdr(); 144 145 const HDR_SIZE_SHIFT: u32 = 16; 146 const HDR_SIZE_MASK: u32 = 0xffff0000; 147 ((hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT).into_safe_cast() 148 } 149 150 fn imem_sec_load_params(&self) -> FalconDmaLoadTarget; 151 fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget>; 152 fn dmem_load_params(&self) -> FalconDmaLoadTarget; 153 } 154 155 impl FalconUCodeDescriptor for FalconUCodeDescV2 { 156 fn hdr(&self) -> u32 { 157 self.hdr 158 } 159 fn imem_load_size(&self) -> u32 { 160 self.imem_load_size 161 } 162 fn interface_offset(&self) -> u32 { 163 self.interface_offset 164 } 165 fn dmem_load_size(&self) -> u32 { 166 self.dmem_load_size 167 } 168 fn pkc_data_offset(&self) -> u32 { 169 0 170 } 171 fn engine_id_mask(&self) -> u16 { 172 0 173 } 174 fn ucode_id(&self) -> u8 { 175 0 176 } 177 fn signature_count(&self) -> u8 { 178 0 179 } 180 fn signature_versions(&self) -> u16 { 181 0 182 } 183 184 fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { 185 // `imem_sec_base` is the *virtual* start address of the secure IMEM segment, so subtract 186 // `imem_virt_base` to get its physical offset. 187 let imem_sec_start = self.imem_sec_base.saturating_sub(self.imem_virt_base); 188 189 FalconDmaLoadTarget { 190 src_start: imem_sec_start, 191 dst_start: self.imem_phys_base.saturating_add(imem_sec_start), 192 len: self.imem_sec_size, 193 } 194 } 195 196 fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> { 197 Some(FalconDmaLoadTarget { 198 // Non-secure code always starts at offset 0. 199 src_start: 0, 200 dst_start: self.imem_phys_base, 201 // `imem_load_size` includes the size of the secure segment, so subtract it to 202 // get the correct amount of data to copy. 203 len: self.imem_load_size.saturating_sub(self.imem_sec_size), 204 }) 205 } 206 207 fn dmem_load_params(&self) -> FalconDmaLoadTarget { 208 FalconDmaLoadTarget { 209 src_start: self.dmem_offset, 210 dst_start: self.dmem_phys_base, 211 len: self.dmem_load_size, 212 } 213 } 214 } 215 216 impl FalconUCodeDescriptor for FalconUCodeDescV3 { 217 fn hdr(&self) -> u32 { 218 self.hdr 219 } 220 fn imem_load_size(&self) -> u32 { 221 self.imem_load_size 222 } 223 fn interface_offset(&self) -> u32 { 224 self.interface_offset 225 } 226 fn dmem_load_size(&self) -> u32 { 227 self.dmem_load_size 228 } 229 fn pkc_data_offset(&self) -> u32 { 230 self.pkc_data_offset 231 } 232 fn engine_id_mask(&self) -> u16 { 233 self.engine_id_mask 234 } 235 fn ucode_id(&self) -> u8 { 236 self.ucode_id 237 } 238 fn signature_count(&self) -> u8 { 239 self.signature_count 240 } 241 fn signature_versions(&self) -> u16 { 242 self.signature_versions 243 } 244 245 fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { 246 FalconDmaLoadTarget { 247 // IMEM segment always starts at offset 0. 248 src_start: 0, 249 dst_start: self.imem_phys_base, 250 len: self.imem_load_size, 251 } 252 } 253 254 fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> { 255 // Not used on V3 platforms 256 None 257 } 258 259 fn dmem_load_params(&self) -> FalconDmaLoadTarget { 260 FalconDmaLoadTarget { 261 // DMEM segment starts right after the IMEM one. 262 src_start: self.imem_load_size, 263 dst_start: self.dmem_phys_base, 264 len: self.dmem_load_size, 265 } 266 } 267 } 268 269 /// Trait implemented by types defining the signed state of a firmware. 270 trait SignedState {} 271 272 /// Type indicating that the firmware must be signed before it can be used. 273 struct Unsigned; 274 impl SignedState for Unsigned {} 275 276 /// Type indicating that the firmware is signed and ready to be loaded. 277 struct Signed; 278 impl SignedState for Signed {} 279 280 /// Microcode to be loaded into a specific falcon. 281 /// 282 /// This is module-local and meant for sub-modules to use internally. 283 /// 284 /// After construction, a firmware is [`Unsigned`], and must generally be patched with a signature 285 /// before it can be loaded (with an exception for development hardware). The 286 /// [`Self::patch_signature`] and [`Self::no_patch_signature`] methods are used to transition the 287 /// firmware to its [`Signed`] state. 288 // TODO: Consider replacing this with a coherent memory object once `CoherentAllocation` supports 289 // temporary CPU-exclusive access to the object without unsafe methods. 290 struct FirmwareObject<F: FalconFirmware, S: SignedState>(KVVec<u8>, PhantomData<(F, S)>); 291 292 /// Trait for signatures to be patched directly into a given firmware. 293 /// 294 /// This is module-local and meant for sub-modules to use internally. 295 trait FirmwareSignature<F: FalconFirmware>: AsRef<[u8]> {} 296 297 impl<F: FalconFirmware> FirmwareObject<F, Unsigned> { 298 /// Patches the firmware at offset `signature_start` with `signature`. 299 fn patch_signature<S: FirmwareSignature<F>>( 300 mut self, 301 signature: &S, 302 signature_start: usize, 303 ) -> Result<FirmwareObject<F, Signed>> { 304 let signature_bytes = signature.as_ref(); 305 let signature_end = signature_start 306 .checked_add(signature_bytes.len()) 307 .ok_or(EOVERFLOW)?; 308 let dst = self 309 .0 310 .get_mut(signature_start..signature_end) 311 .ok_or(EINVAL)?; 312 313 // PANIC: `dst` and `signature_bytes` have the same length. 314 dst.copy_from_slice(signature_bytes); 315 316 Ok(FirmwareObject(self.0, PhantomData)) 317 } 318 319 /// Mark the firmware as signed without patching it. 320 /// 321 /// This method is used to explicitly confirm that we do not need to sign the firmware, while 322 /// allowing us to continue as if it was. This is typically only needed for development 323 /// hardware. 324 fn no_patch_signature(self) -> FirmwareObject<F, Signed> { 325 FirmwareObject(self.0, PhantomData) 326 } 327 } 328 329 pub(crate) struct ModInfoBuilder<const N: usize>(firmware::ModInfoBuilder<N>); 330 331 impl<const N: usize> ModInfoBuilder<N> { 332 const fn make_entry_file(self, chipset: &str, fw: &str) -> Self { 333 ModInfoBuilder( 334 self.0 335 .new_entry() 336 .push("nvidia/") 337 .push(chipset) 338 .push("/gsp/") 339 .push(fw), 340 ) 341 } 342 343 const fn make_entry_chipset(self, chipset: gpu::Chipset) -> Self { 344 let name = chipset.name(); 345 346 // GSP firmware files are always present. 347 let mut this = self 348 .make_entry_file(name, "gsp_bootloader.tlv") 349 .make_entry_file(name, "gsp.tlv") 350 .make_entry_file(name, "gsp.bin"); 351 352 // Add the firmware files specific to the GSP boot method of `chipset`. 353 let boot_files = boot_firmware_files(chipset); 354 let mut i = 0; 355 while i < boot_files.len() { 356 this = this.make_entry_file(name, boot_files[i]); 357 i += 1; 358 } 359 360 this 361 } 362 363 pub(crate) const fn create( 364 module_name: &'static core::ffi::CStr, 365 ) -> firmware::ModInfoBuilder<N> { 366 let mut this = Self(firmware::ModInfoBuilder::new(module_name)); 367 let mut i = 0; 368 369 while i < gpu::Chipset::ALL.len() { 370 this = this.make_entry_chipset(gpu::Chipset::ALL[i]); 371 i += 1; 372 } 373 374 this.0 375 } 376 } 377