1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Contains structures and functions dedicated to the parsing, building and patching of firmwares 4 //! to be loaded into a given execution unit. 5 6 use kernel::device; 7 use kernel::firmware; 8 use kernel::prelude::*; 9 use kernel::str::CString; 10 11 use crate::gpu; 12 use crate::gpu::Chipset; 13 14 pub(crate) const FIRMWARE_VERSION: &str = "535.113.01"; 15 16 /// Structure encapsulating the firmware blobs required for the GPU to operate. 17 #[expect(dead_code)] 18 pub(crate) struct Firmware { 19 booter_load: firmware::Firmware, 20 booter_unload: firmware::Firmware, 21 bootloader: firmware::Firmware, 22 gsp: firmware::Firmware, 23 } 24 25 impl Firmware { 26 pub(crate) fn new(dev: &device::Device, chipset: Chipset, ver: &str) -> Result<Firmware> { 27 let mut chip_name = CString::try_from_fmt(fmt!("{}", chipset))?; 28 chip_name.make_ascii_lowercase(); 29 30 let request = |name_| { 31 CString::try_from_fmt(fmt!("nvidia/{}/gsp/{}-{}.bin", &*chip_name, name_, ver)) 32 .and_then(|path| firmware::Firmware::request(&path, dev)) 33 }; 34 35 Ok(Firmware { 36 booter_load: request("booter_load")?, 37 booter_unload: request("booter_unload")?, 38 bootloader: request("bootloader")?, 39 gsp: request("gsp")?, 40 }) 41 } 42 } 43 44 /// Structure used to describe some firmwares, notably FWSEC-FRTS. 45 #[repr(C)] 46 #[derive(Debug, Clone)] 47 pub(crate) struct FalconUCodeDescV3 { 48 /// Header defined by `NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC*` in OpenRM. 49 hdr: u32, 50 /// Stored size of the ucode after the header. 51 stored_size: u32, 52 /// Offset in `DMEM` at which the signature is expected to be found. 53 pub(crate) pkc_data_offset: u32, 54 /// Offset after the code segment at which the app headers are located. 55 pub(crate) interface_offset: u32, 56 /// Base address at which to load the code segment into `IMEM`. 57 pub(crate) imem_phys_base: u32, 58 /// Size in bytes of the code to copy into `IMEM`. 59 pub(crate) imem_load_size: u32, 60 /// Virtual `IMEM` address (i.e. `tag`) at which the code should start. 61 pub(crate) imem_virt_base: u32, 62 /// Base address at which to load the data segment into `DMEM`. 63 pub(crate) dmem_phys_base: u32, 64 /// Size in bytes of the data to copy into `DMEM`. 65 pub(crate) dmem_load_size: u32, 66 /// Mask of the falcon engines on which this firmware can run. 67 pub(crate) engine_id_mask: u16, 68 /// ID of the ucode used to infer a fuse register to validate the signature. 69 pub(crate) ucode_id: u8, 70 /// Number of signatures in this firmware. 71 pub(crate) signature_count: u8, 72 /// Versions of the signatures, used to infer a valid signature to use. 73 pub(crate) signature_versions: u16, 74 _reserved: u16, 75 } 76 77 impl FalconUCodeDescV3 { 78 /// Returns the size in bytes of the header. 79 pub(crate) fn size(&self) -> usize { 80 const HDR_SIZE_SHIFT: u32 = 16; 81 const HDR_SIZE_MASK: u32 = 0xffff0000; 82 83 ((self.hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT) as usize 84 } 85 } 86 87 pub(crate) struct ModInfoBuilder<const N: usize>(firmware::ModInfoBuilder<N>); 88 89 impl<const N: usize> ModInfoBuilder<N> { 90 const fn make_entry_file(self, chipset: &str, fw: &str) -> Self { 91 ModInfoBuilder( 92 self.0 93 .new_entry() 94 .push("nvidia/") 95 .push(chipset) 96 .push("/gsp/") 97 .push(fw) 98 .push("-") 99 .push(FIRMWARE_VERSION) 100 .push(".bin"), 101 ) 102 } 103 104 const fn make_entry_chipset(self, chipset: &str) -> Self { 105 self.make_entry_file(chipset, "booter_load") 106 .make_entry_file(chipset, "booter_unload") 107 .make_entry_file(chipset, "bootloader") 108 .make_entry_file(chipset, "gsp") 109 } 110 111 pub(crate) const fn create( 112 module_name: &'static kernel::str::CStr, 113 ) -> firmware::ModInfoBuilder<N> { 114 let mut this = Self(firmware::ModInfoBuilder::new(module_name)); 115 let mut i = 0; 116 117 while i < gpu::Chipset::NAMES.len() { 118 this = this.make_entry_chipset(gpu::Chipset::NAMES[i]); 119 i += 1; 120 } 121 122 this.0 123 } 124 } 125