firmware.rs 14 KB

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