xref: /linux/drivers/gpu/nova-core/firmware.rs (revision ad5157827522aedde98bd0323076cd7f6190fbd0)
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