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 device, 12 firmware, 13 prelude::*, 14 str::CString, 15 transmute::FromBytes, // 16 }; 17 18 use crate::{ 19 falcon::{ 20 FalconDmaLoadTarget, 21 FalconFirmware, // 22 }, 23 gpu, 24 gsp::boot_firmware_files, 25 num::IntoSafeCast, // 26 }; 27 28 pub(crate) mod booter; 29 pub(crate) mod fsp; 30 pub(crate) mod fwsec; 31 pub(crate) mod gsp; 32 pub(crate) mod riscv; 33 pub(crate) mod tlv; 34 35 pub(crate) const FIRMWARE_VERSION: &str = "570.144"; 36 37 /// Requests the GPU firmware `name` suitable for `chipset`, with version `ver`. 38 fn request_firmware( 39 dev: &device::Device, 40 chipset: gpu::Chipset, 41 name: &str, 42 ver: &str, 43 ) -> Result<firmware::Firmware> { 44 let chip_name = chipset.name(); 45 46 CString::try_from_fmt(fmt!("nvidia/{chip_name}/gsp/{name}-{ver}.bin")) 47 .and_then(|path| firmware::Firmware::request(&path, dev)) 48 } 49 50 /// Structure used to describe some firmwares, notably FWSEC-FRTS. 51 #[repr(C)] 52 #[derive(Debug, Clone, FromBytes)] 53 pub(crate) struct FalconUCodeDescV2 { 54 /// Header defined by 'NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC*' in OpenRM. 55 hdr: u32, 56 /// Stored size of the ucode after the header, compressed or uncompressed 57 stored_size: u32, 58 /// Uncompressed size of the ucode. If store_size == uncompressed_size, then the ucode 59 /// is not compressed. 60 pub(crate) uncompressed_size: u32, 61 /// Code entry point 62 pub(crate) virtual_entry: u32, 63 /// Offset after the code segment at which the Application Interface Table headers are located. 64 pub(crate) interface_offset: u32, 65 /// Base address at which to load the code segment into 'IMEM'. 66 pub(crate) imem_phys_base: u32, 67 /// Size in bytes of the code to copy into 'IMEM' (includes both secure and non-secure 68 /// segments). 69 pub(crate) imem_load_size: u32, 70 /// Virtual 'IMEM' address (i.e. 'tag') at which the code should start. 71 pub(crate) imem_virt_base: u32, 72 /// Virtual address of secure IMEM segment. 73 pub(crate) imem_sec_base: u32, 74 /// Size of secure IMEM segment. 75 pub(crate) imem_sec_size: u32, 76 /// Offset into stored (uncompressed) image at which DMEM begins. 77 pub(crate) dmem_offset: u32, 78 /// Base address at which to load the data segment into 'DMEM'. 79 pub(crate) dmem_phys_base: u32, 80 /// Size in bytes of the data to copy into 'DMEM'. 81 pub(crate) dmem_load_size: u32, 82 /// "Alternate" Size of data to load into IMEM. 83 pub(crate) alt_imem_load_size: u32, 84 /// "Alternate" Size of data to load into DMEM. 85 pub(crate) alt_dmem_load_size: u32, 86 } 87 88 /// Structure used to describe some firmwares, notably FWSEC-FRTS. 89 #[repr(C)] 90 #[derive(Debug, Clone, FromBytes)] 91 pub(crate) struct FalconUCodeDescV3 { 92 /// Header defined by `NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC*` in OpenRM. 93 hdr: u32, 94 /// Stored size of the ucode after the header. 95 stored_size: u32, 96 /// Offset in `DMEM` at which the signature is expected to be found. 97 pub(crate) pkc_data_offset: u32, 98 /// Offset after the code segment at which the app headers are located. 99 pub(crate) interface_offset: u32, 100 /// Base address at which to load the code segment into `IMEM`. 101 pub(crate) imem_phys_base: u32, 102 /// Size in bytes of the code to copy into `IMEM`. 103 pub(crate) imem_load_size: u32, 104 /// Virtual `IMEM` address (i.e. `tag`) at which the code should start. 105 pub(crate) imem_virt_base: u32, 106 /// Base address at which to load the data segment into `DMEM`. 107 pub(crate) dmem_phys_base: u32, 108 /// Size in bytes of the data to copy into `DMEM`. 109 pub(crate) dmem_load_size: u32, 110 /// Mask of the falcon engines on which this firmware can run. 111 pub(crate) engine_id_mask: u16, 112 /// ID of the ucode used to infer a fuse register to validate the signature. 113 pub(crate) ucode_id: u8, 114 /// Number of signatures in this firmware. 115 pub(crate) signature_count: u8, 116 /// Versions of the signatures, used to infer a valid signature to use. 117 pub(crate) signature_versions: u16, 118 _reserved: u16, 119 } 120 121 /// Enum wrapping the different versions of Falcon microcode descriptors. 122 /// 123 /// This allows handling both V2 and V3 descriptor formats through a 124 /// unified type, providing version-agnostic access to firmware metadata 125 /// via the [`FalconUCodeDescriptor`] trait. 126 #[derive(Debug, Clone)] 127 pub(crate) enum FalconUCodeDesc { 128 V2(FalconUCodeDescV2), 129 V3(FalconUCodeDescV3), 130 } 131 132 impl Deref for FalconUCodeDesc { 133 type Target = dyn FalconUCodeDescriptor; 134 135 fn deref(&self) -> &Self::Target { 136 match self { 137 FalconUCodeDesc::V2(v2) => v2, 138 FalconUCodeDesc::V3(v3) => v3, 139 } 140 } 141 } 142 143 /// Trait providing a common interface for accessing Falcon microcode descriptor fields. 144 /// 145 /// This trait abstracts over the different descriptor versions ([`FalconUCodeDescV2`] and 146 /// [`FalconUCodeDescV3`]), allowing code to work with firmware metadata without needing to 147 /// know the specific descriptor version. Fields not present return zero. 148 pub(crate) trait FalconUCodeDescriptor { 149 fn hdr(&self) -> u32; 150 fn imem_load_size(&self) -> u32; 151 fn interface_offset(&self) -> u32; 152 fn dmem_load_size(&self) -> u32; 153 fn pkc_data_offset(&self) -> u32; 154 fn engine_id_mask(&self) -> u16; 155 fn ucode_id(&self) -> u8; 156 fn signature_count(&self) -> u8; 157 fn signature_versions(&self) -> u16; 158 159 /// Returns the size in bytes of the header. 160 fn size(&self) -> usize { 161 let hdr = self.hdr(); 162 163 const HDR_SIZE_SHIFT: u32 = 16; 164 const HDR_SIZE_MASK: u32 = 0xffff0000; 165 ((hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT).into_safe_cast() 166 } 167 168 fn imem_sec_load_params(&self) -> FalconDmaLoadTarget; 169 fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget>; 170 fn dmem_load_params(&self) -> FalconDmaLoadTarget; 171 } 172 173 impl FalconUCodeDescriptor for FalconUCodeDescV2 { 174 fn hdr(&self) -> u32 { 175 self.hdr 176 } 177 fn imem_load_size(&self) -> u32 { 178 self.imem_load_size 179 } 180 fn interface_offset(&self) -> u32 { 181 self.interface_offset 182 } 183 fn dmem_load_size(&self) -> u32 { 184 self.dmem_load_size 185 } 186 fn pkc_data_offset(&self) -> u32 { 187 0 188 } 189 fn engine_id_mask(&self) -> u16 { 190 0 191 } 192 fn ucode_id(&self) -> u8 { 193 0 194 } 195 fn signature_count(&self) -> u8 { 196 0 197 } 198 fn signature_versions(&self) -> u16 { 199 0 200 } 201 202 fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { 203 // `imem_sec_base` is the *virtual* start address of the secure IMEM segment, so subtract 204 // `imem_virt_base` to get its physical offset. 205 let imem_sec_start = self.imem_sec_base.saturating_sub(self.imem_virt_base); 206 207 FalconDmaLoadTarget { 208 src_start: imem_sec_start, 209 dst_start: self.imem_phys_base.saturating_add(imem_sec_start), 210 len: self.imem_sec_size, 211 } 212 } 213 214 fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> { 215 Some(FalconDmaLoadTarget { 216 // Non-secure code always starts at offset 0. 217 src_start: 0, 218 dst_start: self.imem_phys_base, 219 // `imem_load_size` includes the size of the secure segment, so subtract it to 220 // get the correct amount of data to copy. 221 len: self.imem_load_size.saturating_sub(self.imem_sec_size), 222 }) 223 } 224 225 fn dmem_load_params(&self) -> FalconDmaLoadTarget { 226 FalconDmaLoadTarget { 227 src_start: self.dmem_offset, 228 dst_start: self.dmem_phys_base, 229 len: self.dmem_load_size, 230 } 231 } 232 } 233 234 impl FalconUCodeDescriptor for FalconUCodeDescV3 { 235 fn hdr(&self) -> u32 { 236 self.hdr 237 } 238 fn imem_load_size(&self) -> u32 { 239 self.imem_load_size 240 } 241 fn interface_offset(&self) -> u32 { 242 self.interface_offset 243 } 244 fn dmem_load_size(&self) -> u32 { 245 self.dmem_load_size 246 } 247 fn pkc_data_offset(&self) -> u32 { 248 self.pkc_data_offset 249 } 250 fn engine_id_mask(&self) -> u16 { 251 self.engine_id_mask 252 } 253 fn ucode_id(&self) -> u8 { 254 self.ucode_id 255 } 256 fn signature_count(&self) -> u8 { 257 self.signature_count 258 } 259 fn signature_versions(&self) -> u16 { 260 self.signature_versions 261 } 262 263 fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { 264 FalconDmaLoadTarget { 265 // IMEM segment always starts at offset 0. 266 src_start: 0, 267 dst_start: self.imem_phys_base, 268 len: self.imem_load_size, 269 } 270 } 271 272 fn imem_ns_load_params(&self) -> Option<FalconDmaLoadTarget> { 273 // Not used on V3 platforms 274 None 275 } 276 277 fn dmem_load_params(&self) -> FalconDmaLoadTarget { 278 FalconDmaLoadTarget { 279 // DMEM segment starts right after the IMEM one. 280 src_start: self.imem_load_size, 281 dst_start: self.dmem_phys_base, 282 len: self.dmem_load_size, 283 } 284 } 285 } 286 287 /// Trait implemented by types defining the signed state of a firmware. 288 trait SignedState {} 289 290 /// Type indicating that the firmware must be signed before it can be used. 291 struct Unsigned; 292 impl SignedState for Unsigned {} 293 294 /// Type indicating that the firmware is signed and ready to be loaded. 295 struct Signed; 296 impl SignedState for Signed {} 297 298 /// Microcode to be loaded into a specific falcon. 299 /// 300 /// This is module-local and meant for sub-modules to use internally. 301 /// 302 /// After construction, a firmware is [`Unsigned`], and must generally be patched with a signature 303 /// before it can be loaded (with an exception for development hardware). The 304 /// [`Self::patch_signature`] and [`Self::no_patch_signature`] methods are used to transition the 305 /// firmware to its [`Signed`] state. 306 // TODO: Consider replacing this with a coherent memory object once `CoherentAllocation` supports 307 // temporary CPU-exclusive access to the object without unsafe methods. 308 struct FirmwareObject<F: FalconFirmware, S: SignedState>(KVVec<u8>, PhantomData<(F, S)>); 309 310 /// Trait for signatures to be patched directly into a given firmware. 311 /// 312 /// This is module-local and meant for sub-modules to use internally. 313 trait FirmwareSignature<F: FalconFirmware>: AsRef<[u8]> {} 314 315 impl<F: FalconFirmware> FirmwareObject<F, Unsigned> { 316 /// Patches the firmware at offset `signature_start` with `signature`. 317 fn patch_signature<S: FirmwareSignature<F>>( 318 mut self, 319 signature: &S, 320 signature_start: usize, 321 ) -> Result<FirmwareObject<F, Signed>> { 322 let signature_bytes = signature.as_ref(); 323 let signature_end = signature_start 324 .checked_add(signature_bytes.len()) 325 .ok_or(EOVERFLOW)?; 326 let dst = self 327 .0 328 .get_mut(signature_start..signature_end) 329 .ok_or(EINVAL)?; 330 331 // PANIC: `dst` and `signature_bytes` have the same length. 332 dst.copy_from_slice(signature_bytes); 333 334 Ok(FirmwareObject(self.0, PhantomData)) 335 } 336 337 /// Mark the firmware as signed without patching it. 338 /// 339 /// This method is used to explicitly confirm that we do not need to sign the firmware, while 340 /// allowing us to continue as if it was. This is typically only needed for development 341 /// hardware. 342 fn no_patch_signature(self) -> FirmwareObject<F, Signed> { 343 FirmwareObject(self.0, PhantomData) 344 } 345 } 346 347 /// Header common to most firmware files. 348 #[repr(C)] 349 #[derive(Debug, Clone)] 350 struct BinHdr { 351 /// Magic number, must be `0x10de`. 352 bin_magic: u32, 353 /// Version of the header. 354 bin_ver: u32, 355 /// Size in bytes of the binary (to be ignored). 356 bin_size: u32, 357 /// Offset of the start of the application-specific header. 358 header_offset: u32, 359 /// Offset of the start of the data payload. 360 data_offset: u32, 361 /// Size in bytes of the data payload. 362 data_size: u32, 363 } 364 365 // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. 366 unsafe impl FromBytes for BinHdr {} 367 368 pub(crate) struct ModInfoBuilder<const N: usize>(firmware::ModInfoBuilder<N>); 369 370 impl<const N: usize> ModInfoBuilder<N> { 371 const fn make_entry_file(self, chipset: &str, fw: &str) -> Self { 372 ModInfoBuilder( 373 self.0 374 .new_entry() 375 .push("nvidia/") 376 .push(chipset) 377 .push("/gsp/") 378 .push(fw) 379 .push("-") 380 .push(FIRMWARE_VERSION) 381 .push(".bin"), 382 ) 383 } 384 385 const fn make_entry_chipset(self, chipset: gpu::Chipset) -> Self { 386 let name = chipset.name(); 387 388 // GSP firmware files are always present. 389 let mut this = self 390 .make_entry_file(name, "bootloader") 391 .make_entry_file(name, "gsp"); 392 393 // Add the firmware files specific to the GSP boot method of `chipset`. 394 let boot_files = boot_firmware_files(chipset); 395 let mut i = 0; 396 while i < boot_files.len() { 397 this = this.make_entry_file(name, boot_files[i]); 398 i += 1; 399 } 400 401 this 402 } 403 404 pub(crate) const fn create( 405 module_name: &'static core::ffi::CStr, 406 ) -> firmware::ModInfoBuilder<N> { 407 let mut this = Self(firmware::ModInfoBuilder::new(module_name)); 408 let mut i = 0; 409 410 while i < gpu::Chipset::ALL.len() { 411 this = this.make_entry_chipset(gpu::Chipset::ALL[i]); 412 i += 1; 413 } 414 415 this.0 416 } 417 } 418 419 /// Ad-hoc and temporary module to extract sections from ELF images. 420 /// 421 /// Some firmware images are currently packaged as ELF files, where sections names are used as keys 422 /// to specific and related bits of data. Future firmware versions are scheduled to move away from 423 /// that scheme before nova-core becomes stable, which means this module will eventually be 424 /// removed. 425 mod elf { 426 use kernel::{ 427 bindings, 428 prelude::*, 429 transmute::FromBytes, // 430 }; 431 432 /// Trait to abstract over ELF header differences. 433 trait ElfHeader: FromBytes { 434 fn shnum(&self) -> u16; 435 fn shoff(&self) -> u64; 436 fn shstrndx(&self) -> u16; 437 } 438 439 /// Trait to abstract over ELF section-header differences. 440 trait ElfSectionHeader: FromBytes { 441 fn name(&self) -> u32; 442 fn offset(&self) -> u64; 443 fn size(&self) -> u64; 444 } 445 446 /// Trait describing a matching ELF header and section-header format. 447 trait ElfFormat { 448 type Header: ElfHeader; 449 type SectionHeader: ElfSectionHeader; 450 } 451 452 /// Newtype to provide a [`FromBytes`] implementation. 453 #[repr(transparent)] 454 struct Elf64Hdr(bindings::elf64_hdr); 455 // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. 456 unsafe impl FromBytes for Elf64Hdr {} 457 458 impl ElfHeader for Elf64Hdr { 459 fn shnum(&self) -> u16 { 460 self.0.e_shnum 461 } 462 463 fn shoff(&self) -> u64 { 464 self.0.e_shoff 465 } 466 467 fn shstrndx(&self) -> u16 { 468 self.0.e_shstrndx 469 } 470 } 471 472 #[repr(transparent)] 473 struct Elf64SHdr(bindings::elf64_shdr); 474 // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. 475 unsafe impl FromBytes for Elf64SHdr {} 476 477 impl ElfSectionHeader for Elf64SHdr { 478 fn name(&self) -> u32 { 479 self.0.sh_name 480 } 481 482 fn offset(&self) -> u64 { 483 self.0.sh_offset 484 } 485 486 fn size(&self) -> u64 { 487 self.0.sh_size 488 } 489 } 490 491 struct Elf64Format; 492 493 impl ElfFormat for Elf64Format { 494 type Header = Elf64Hdr; 495 type SectionHeader = Elf64SHdr; 496 } 497 498 /// Newtype to provide [`FromBytes`] and [`ElfHeader`] implementations for ELF32. 499 #[repr(transparent)] 500 struct Elf32Hdr(bindings::elf32_hdr); 501 // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. 502 unsafe impl FromBytes for Elf32Hdr {} 503 504 impl ElfHeader for Elf32Hdr { 505 fn shnum(&self) -> u16 { 506 self.0.e_shnum 507 } 508 509 fn shoff(&self) -> u64 { 510 u64::from(self.0.e_shoff) 511 } 512 513 fn shstrndx(&self) -> u16 { 514 self.0.e_shstrndx 515 } 516 } 517 518 /// Newtype to provide [`FromBytes`] and [`ElfSectionHeader`] implementations for ELF32. 519 #[repr(transparent)] 520 struct Elf32SHdr(bindings::elf32_shdr); 521 // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. 522 unsafe impl FromBytes for Elf32SHdr {} 523 524 impl ElfSectionHeader for Elf32SHdr { 525 fn name(&self) -> u32 { 526 self.0.sh_name 527 } 528 529 fn offset(&self) -> u64 { 530 u64::from(self.0.sh_offset) 531 } 532 533 fn size(&self) -> u64 { 534 u64::from(self.0.sh_size) 535 } 536 } 537 538 struct Elf32Format; 539 540 impl ElfFormat for Elf32Format { 541 type Header = Elf32Hdr; 542 type SectionHeader = Elf32SHdr; 543 } 544 545 /// Returns a NULL-terminated string from the ELF image at `offset`. 546 fn elf_str(elf: &[u8], offset: u64) -> Option<&str> { 547 let idx = usize::try_from(offset).ok()?; 548 let bytes = elf.get(idx..)?; 549 CStr::from_bytes_until_nul(bytes).ok()?.to_str().ok() 550 } 551 552 fn elf_section_generic<'a, F>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> 553 where 554 F: ElfFormat, 555 { 556 let hdr = F::Header::from_bytes(elf.get(0..size_of::<F::Header>())?)?; 557 558 let shdr_num = usize::from(hdr.shnum()); 559 let shdr_start = usize::try_from(hdr.shoff()).ok()?; 560 let shdr_end = shdr_num 561 .checked_mul(size_of::<F::SectionHeader>()) 562 .and_then(|v| v.checked_add(shdr_start))?; 563 564 // Get all the section headers as an iterator over byte chunks. 565 let shdr_bytes = elf.get(shdr_start..shdr_end)?; 566 let mut shdr_iter = shdr_bytes.chunks_exact(size_of::<F::SectionHeader>()); 567 568 // Get the strings table. 569 let strhdr = shdr_iter 570 .clone() 571 .nth(usize::from(hdr.shstrndx())) 572 .and_then(F::SectionHeader::from_bytes)?; 573 574 // Find the section which name matches `name` and return it. 575 shdr_iter.find_map(|sh_bytes| { 576 let sh = F::SectionHeader::from_bytes(sh_bytes)?; 577 let name_offset = strhdr.offset().checked_add(u64::from(sh.name()))?; 578 let section_name = elf_str(elf, name_offset)?; 579 580 if section_name != name { 581 return None; 582 } 583 584 let start = usize::try_from(sh.offset()).ok()?; 585 let end = usize::try_from(sh.size()) 586 .ok() 587 .and_then(|sz| start.checked_add(sz))?; 588 589 elf.get(start..end) 590 }) 591 } 592 593 /// Extract the section with name `name` from the ELF64 image `elf`. 594 fn elf64_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> { 595 elf_section_generic::<Elf64Format>(elf, name) 596 } 597 598 /// Extract the section with name `name` from the ELF32 image `elf`. 599 fn elf32_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> { 600 elf_section_generic::<Elf32Format>(elf, name) 601 } 602 603 /// Automatically detects ELF32 vs ELF64 based on the ELF header. 604 pub(super) fn elf_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> { 605 // ELF identification: a 4-byte magic followed by a class byte (32- vs 64-bit). 606 const ELFMAG: &[u8] = b"\x7fELF"; 607 const SELFMAG: usize = ELFMAG.len(); 608 const EI_CLASS: usize = 4; 609 const ELFCLASS32: u8 = 1; 610 const ELFCLASS64: u8 = 2; 611 612 if elf.get(0..SELFMAG) != Some(ELFMAG) { 613 return None; 614 } 615 616 match *elf.get(EI_CLASS)? { 617 ELFCLASS32 => elf32_section(elf, name), 618 ELFCLASS64 => elf64_section(elf, name), 619 _ => None, 620 } 621 } 622 } 623