[PATCH v5 26/38] gpu: nova-core: Hopper/Blackwell: add FMC signature extraction

From: John Hubbard

Date: Fri Feb 20 2026 - 21:20:09 EST


Add extract_fmc_signatures() which extracts SHA-384 hash, RSA public
key, and RSA signature from FMC ELF32 firmware sections. These are
needed for FSP Chain of Trust verification.

Signed-off-by: John Hubbard <jhubbard@xxxxxxxxxx>
---
drivers/gpu/nova-core/firmware.rs | 1 -
drivers/gpu/nova-core/fsp.rs | 61 ++++++++++++++++++++++++++++++-
2 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs
index 823d2232081e..eaced3d42728 100644
--- a/drivers/gpu/nova-core/firmware.rs
+++ b/drivers/gpu/nova-core/firmware.rs
@@ -27,7 +27,6 @@
},
};

-#[expect(unused)]
pub(crate) use elf::elf_section;

pub(crate) mod booter;
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index 15731d24d0c5..29707578d4d4 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -112,7 +112,6 @@ unsafe impl FromBytes for GspFmcBootParams {}

/// Structure to hold FMC signatures.
#[derive(Debug, Clone, Copy)]
-#[expect(dead_code)]
pub(crate) struct FmcSignatures {
hash384: [u8; FSP_HASH_SIZE],
public_key: [u8; FSP_PKEY_SIZE],
@@ -216,4 +215,64 @@ pub(crate) fn wait_secure_boot(
})
.map(|_| ())
}
+
+ /// Extract FMC firmware signatures for Chain of Trust verification.
+ ///
+ /// Extracts real cryptographic signatures from FMC ELF32 firmware sections.
+ /// Returns signatures in a heap-allocated structure to prevent stack overflow.
+ #[expect(dead_code)]
+ pub(crate) fn extract_fmc_signatures(
+ dev: &device::Device<device::Bound>,
+ fmc_fw_data: &[u8],
+ ) -> Result<KBox<FmcSignatures>> {
+ let hash_section = crate::firmware::elf_section(fmc_fw_data, "hash")
+ .ok_or(EINVAL)
+ .inspect_err(|_| dev_err!(dev, "FMC firmware missing 'hash' section\n"))?;
+
+ let pkey_section = crate::firmware::elf_section(fmc_fw_data, "publickey")
+ .ok_or(EINVAL)
+ .inspect_err(|_| dev_err!(dev, "FMC firmware missing 'publickey' section\n"))?;
+
+ let sig_section = crate::firmware::elf_section(fmc_fw_data, "signature")
+ .ok_or(EINVAL)
+ .inspect_err(|_| dev_err!(dev, "FMC firmware missing 'signature' section\n"))?;
+
+ if hash_section.len() != FSP_HASH_SIZE {
+ dev_err!(
+ dev,
+ "FMC hash section size {} != expected {}\n",
+ hash_section.len(),
+ FSP_HASH_SIZE
+ );
+ return Err(EINVAL);
+ }
+
+ if pkey_section.len() > FSP_PKEY_SIZE {
+ dev_err!(
+ dev,
+ "FMC publickey section size {} > maximum {}\n",
+ pkey_section.len(),
+ FSP_PKEY_SIZE
+ );
+ return Err(EINVAL);
+ }
+
+ if sig_section.len() > FSP_SIG_SIZE {
+ dev_err!(
+ dev,
+ "FMC signature section size {} > maximum {}\n",
+ sig_section.len(),
+ FSP_SIG_SIZE
+ );
+ return Err(EINVAL);
+ }
+
+ let mut signatures = KBox::new(FmcSignatures::default(), GFP_KERNEL)?;
+
+ signatures.hash384.copy_from_slice(hash_section);
+ signatures.public_key[..pkey_section.len()].copy_from_slice(pkey_section);
+ signatures.signature[..sig_section.len()].copy_from_slice(sig_section);
+
+ Ok(signatures)
+ }
}
--
2.53.0