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 // A firmware blob starting with a `BinHdr`. 369 struct BinFirmware<'a> { 370 hdr: BinHdr, 371 fw: &'a [u8], 372 } 373 374 impl<'a> BinFirmware<'a> { 375 /// Interpret `fw` as a firmware image starting with a [`BinHdr`], and returns the 376 /// corresponding [`BinFirmware`] that can be used to extract its payload. 377 fn new(fw: &'a firmware::Firmware) -> Result<Self> { 378 const BIN_MAGIC: u32 = 0x10de; 379 let fw = fw.data(); 380 381 fw.get(0..size_of::<BinHdr>()) 382 // Extract header. 383 .and_then(BinHdr::from_bytes_copy) 384 // Validate header. 385 .filter(|hdr| hdr.bin_magic == BIN_MAGIC) 386 .map(|hdr| Self { hdr, fw }) 387 .ok_or(EINVAL) 388 } 389 } 390 391 pub(crate) struct ModInfoBuilder<const N: usize>(firmware::ModInfoBuilder<N>); 392 393 impl<const N: usize> ModInfoBuilder<N> { 394 const fn make_entry_file(self, chipset: &str, fw: &str) -> Self { 395 ModInfoBuilder( 396 self.0 397 .new_entry() 398 .push("nvidia/") 399 .push(chipset) 400 .push("/gsp/") 401 .push(fw) 402 .push("-") 403 .push(FIRMWARE_VERSION) 404 .push(".bin"), 405 ) 406 } 407 408 const fn make_entry_chipset(self, chipset: gpu::Chipset) -> Self { 409 let name = chipset.name(); 410 411 // GSP firmware files are always present. 412 let mut this = self 413 .make_entry_file(name, "bootloader") 414 .make_entry_file(name, "gsp"); 415 416 // Add the firmware files specific to the GSP boot method of `chipset`. 417 let boot_files = boot_firmware_files(chipset); 418 let mut i = 0; 419 while i < boot_files.len() { 420 this = this.make_entry_file(name, boot_files[i]); 421 i += 1; 422 } 423 424 this 425 } 426 427 pub(crate) const fn create( 428 module_name: &'static core::ffi::CStr, 429 ) -> firmware::ModInfoBuilder<N> { 430 let mut this = Self(firmware::ModInfoBuilder::new(module_name)); 431 let mut i = 0; 432 433 while i < gpu::Chipset::ALL.len() { 434 this = this.make_entry_chipset(gpu::Chipset::ALL[i]); 435 i += 1; 436 } 437 438 this.0 439 } 440 } 441 442 /// Ad-hoc and temporary module to extract sections from ELF images. 443 /// 444 /// Some firmware images are currently packaged as ELF files, where sections names are used as keys 445 /// to specific and related bits of data. Future firmware versions are scheduled to move away from 446 /// that scheme before nova-core becomes stable, which means this module will eventually be 447 /// removed. 448 mod elf { 449 use kernel::{ 450 bindings, 451 prelude::*, 452 transmute::FromBytes, // 453 }; 454 455 /// Trait to abstract over ELF header differences. 456 trait ElfHeader: FromBytes { 457 fn shnum(&self) -> u16; 458 fn shoff(&self) -> u64; 459 fn shstrndx(&self) -> u16; 460 } 461 462 /// Trait to abstract over ELF section-header differences. 463 trait ElfSectionHeader: FromBytes { 464 fn name(&self) -> u32; 465 fn offset(&self) -> u64; 466 fn size(&self) -> u64; 467 } 468 469 /// Trait describing a matching ELF header and section-header format. 470 trait ElfFormat { 471 type Header: ElfHeader; 472 type SectionHeader: ElfSectionHeader; 473 } 474 475 /// Newtype to provide a [`FromBytes`] implementation. 476 #[repr(transparent)] 477 struct Elf64Hdr(bindings::elf64_hdr); 478 // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. 479 unsafe impl FromBytes for Elf64Hdr {} 480 481 impl ElfHeader for Elf64Hdr { 482 fn shnum(&self) -> u16 { 483 self.0.e_shnum 484 } 485 486 fn shoff(&self) -> u64 { 487 self.0.e_shoff 488 } 489 490 fn shstrndx(&self) -> u16 { 491 self.0.e_shstrndx 492 } 493 } 494 495 #[repr(transparent)] 496 struct Elf64SHdr(bindings::elf64_shdr); 497 // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. 498 unsafe impl FromBytes for Elf64SHdr {} 499 500 impl ElfSectionHeader for Elf64SHdr { 501 fn name(&self) -> u32 { 502 self.0.sh_name 503 } 504 505 fn offset(&self) -> u64 { 506 self.0.sh_offset 507 } 508 509 fn size(&self) -> u64 { 510 self.0.sh_size 511 } 512 } 513 514 struct Elf64Format; 515 516 impl ElfFormat for Elf64Format { 517 type Header = Elf64Hdr; 518 type SectionHeader = Elf64SHdr; 519 } 520 521 /// Newtype to provide [`FromBytes`] and [`ElfHeader`] implementations for ELF32. 522 #[repr(transparent)] 523 struct Elf32Hdr(bindings::elf32_hdr); 524 // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. 525 unsafe impl FromBytes for Elf32Hdr {} 526 527 impl ElfHeader for Elf32Hdr { 528 fn shnum(&self) -> u16 { 529 self.0.e_shnum 530 } 531 532 fn shoff(&self) -> u64 { 533 u64::from(self.0.e_shoff) 534 } 535 536 fn shstrndx(&self) -> u16 { 537 self.0.e_shstrndx 538 } 539 } 540 541 /// Newtype to provide [`FromBytes`] and [`ElfSectionHeader`] implementations for ELF32. 542 #[repr(transparent)] 543 struct Elf32SHdr(bindings::elf32_shdr); 544 // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. 545 unsafe impl FromBytes for Elf32SHdr {} 546 547 impl ElfSectionHeader for Elf32SHdr { 548 fn name(&self) -> u32 { 549 self.0.sh_name 550 } 551 552 fn offset(&self) -> u64 { 553 u64::from(self.0.sh_offset) 554 } 555 556 fn size(&self) -> u64 { 557 u64::from(self.0.sh_size) 558 } 559 } 560 561 struct Elf32Format; 562 563 impl ElfFormat for Elf32Format { 564 type Header = Elf32Hdr; 565 type SectionHeader = Elf32SHdr; 566 } 567 568 /// Returns a NULL-terminated string from the ELF image at `offset`. 569 fn elf_str(elf: &[u8], offset: u64) -> Option<&str> { 570 let idx = usize::try_from(offset).ok()?; 571 let bytes = elf.get(idx..)?; 572 CStr::from_bytes_until_nul(bytes).ok()?.to_str().ok() 573 } 574 575 fn elf_section_generic<'a, F>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> 576 where 577 F: ElfFormat, 578 { 579 let hdr = F::Header::from_bytes(elf.get(0..size_of::<F::Header>())?)?; 580 581 let shdr_num = usize::from(hdr.shnum()); 582 let shdr_start = usize::try_from(hdr.shoff()).ok()?; 583 let shdr_end = shdr_num 584 .checked_mul(size_of::<F::SectionHeader>()) 585 .and_then(|v| v.checked_add(shdr_start))?; 586 587 // Get all the section headers as an iterator over byte chunks. 588 let shdr_bytes = elf.get(shdr_start..shdr_end)?; 589 let mut shdr_iter = shdr_bytes.chunks_exact(size_of::<F::SectionHeader>()); 590 591 // Get the strings table. 592 let strhdr = shdr_iter 593 .clone() 594 .nth(usize::from(hdr.shstrndx())) 595 .and_then(F::SectionHeader::from_bytes)?; 596 597 // Find the section which name matches `name` and return it. 598 shdr_iter.find_map(|sh_bytes| { 599 let sh = F::SectionHeader::from_bytes(sh_bytes)?; 600 let name_offset = strhdr.offset().checked_add(u64::from(sh.name()))?; 601 let section_name = elf_str(elf, name_offset)?; 602 603 if section_name != name { 604 return None; 605 } 606 607 let start = usize::try_from(sh.offset()).ok()?; 608 let end = usize::try_from(sh.size()) 609 .ok() 610 .and_then(|sz| start.checked_add(sz))?; 611 612 elf.get(start..end) 613 }) 614 } 615 616 /// Extract the section with name `name` from the ELF64 image `elf`. 617 fn elf64_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> { 618 elf_section_generic::<Elf64Format>(elf, name) 619 } 620 621 /// Extract the section with name `name` from the ELF32 image `elf`. 622 fn elf32_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> { 623 elf_section_generic::<Elf32Format>(elf, name) 624 } 625 626 /// Automatically detects ELF32 vs ELF64 based on the ELF header. 627 pub(super) fn elf_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> { 628 // ELF identification: a 4-byte magic followed by a class byte (32- vs 64-bit). 629 const ELFMAG: &[u8] = b"\x7fELF"; 630 const SELFMAG: usize = ELFMAG.len(); 631 const EI_CLASS: usize = 4; 632 const ELFCLASS32: u8 = 1; 633 const ELFCLASS64: u8 = 2; 634 635 if elf.get(0..SELFMAG) != Some(ELFMAG) { 636 return None; 637 } 638 639 match *elf.get(EI_CLASS)? { 640 ELFCLASS32 => elf32_section(elf, name), 641 ELFCLASS64 => elf64_section(elf, name), 642 _ => None, 643 } 644 } 645 } 646