[PATCH v6 23/34] gpu: nova-core: Hopper/Blackwell: add FSP message structures

John Hubbard posted 34 patches 1 month ago
There is a newer version of this series
[PATCH v6 23/34] gpu: nova-core: Hopper/Blackwell: add FSP message structures
Posted by John Hubbard 1 month ago
Add the NVDM COT payload, FSP message, and FSP response structures
needed for FSP Chain of Trust communication. Also add FmcSignatures
to hold the hash, public key, and signature extracted from FMC firmware.

Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
 drivers/gpu/nova-core/firmware.rs |  5 +-
 drivers/gpu/nova-core/fsp.rs      | 78 +++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs
index 6a0a02177f6f..be41e07b8448 100644
--- a/drivers/gpu/nova-core/firmware.rs
+++ b/drivers/gpu/nova-core/firmware.rs
@@ -26,6 +26,9 @@
     },
 };
 
+#[expect(unused)]
+pub(crate) use elf::elf_section;
+
 pub(crate) mod booter;
 pub(crate) mod fsp;
 pub(crate) mod fwsec;
@@ -627,7 +630,7 @@ fn elf32_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> {
     }
 
     /// Automatically detects ELF32 vs ELF64 based on the ELF header.
-    pub(super) fn elf_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> {
+    pub(crate) fn elf_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> {
         // Check ELF magic.
         if elf.len() < 5 || elf.get(0..4)? != b"\x7fELF" {
             return None;
diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
index d464ad325881..15731d24d0c5 100644
--- a/drivers/gpu/nova-core/fsp.rs
+++ b/drivers/gpu/nova-core/fsp.rs
@@ -105,6 +105,84 @@ unsafe impl AsBytes for GspFmcBootParams {}
 // SAFETY: All bit patterns are valid for the primitive fields.
 unsafe impl FromBytes for GspFmcBootParams {}
 
+/// Size constraints for FSP security signatures (Hopper/Blackwell).
+const FSP_HASH_SIZE: usize = 48; // SHA-384 hash
+const FSP_PKEY_SIZE: usize = 384; // RSA-3072 public key
+const FSP_SIG_SIZE: usize = 384; // RSA-3072 signature
+
+/// 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],
+    signature: [u8; FSP_SIG_SIZE],
+}
+
+impl Default for FmcSignatures {
+    fn default() -> Self {
+        Self {
+            hash384: [0u8; FSP_HASH_SIZE],
+            public_key: [0u8; FSP_PKEY_SIZE],
+            signature: [0u8; FSP_SIG_SIZE],
+        }
+    }
+}
+
+/// FSP Command Response payload structure.
+/// NVDM_PAYLOAD_COMMAND_RESPONSE structure.
+#[repr(C, packed)]
+#[derive(Clone, Copy)]
+struct NvdmPayloadCommandResponse {
+    task_id: u32,
+    command_nvdm_type: u32,
+    error_code: u32,
+}
+
+/// NVDM (NVIDIA Device Management) COT (Chain of Trust) payload structure.
+/// This is the main message payload sent to FSP for Chain of Trust.
+#[repr(C, packed)]
+#[derive(Clone, Copy)]
+struct NvdmPayloadCot {
+    version: u16,
+    size: u16,
+    gsp_fmc_sysmem_offset: u64,
+    frts_sysmem_offset: u64,
+    frts_sysmem_size: u32,
+    frts_vidmem_offset: u64,
+    frts_vidmem_size: u32,
+    hash384: [u8; FSP_HASH_SIZE],
+    public_key: [u8; FSP_PKEY_SIZE],
+    signature: [u8; FSP_SIG_SIZE],
+    gsp_boot_args_sysmem_offset: u64,
+}
+
+/// Complete FSP message structure with MCTP and NVDM headers.
+#[repr(C, packed)]
+#[derive(Clone, Copy)]
+#[expect(dead_code)]
+struct FspMessage {
+    mctp_header: u32,
+    nvdm_header: u32,
+    cot: NvdmPayloadCot,
+}
+
+// SAFETY: FspMessage is a packed C struct with only integral fields.
+unsafe impl AsBytes for FspMessage {}
+
+/// Complete FSP response structure with MCTP and NVDM headers.
+#[repr(C, packed)]
+#[derive(Clone, Copy)]
+#[expect(dead_code)]
+struct FspResponse {
+    mctp_header: u32,
+    nvdm_header: u32,
+    response: NvdmPayloadCommandResponse,
+}
+
+// SAFETY: FspResponse is a packed C struct with only integral fields.
+unsafe impl FromBytes for FspResponse {}
+
 /// FSP interface for Hopper/Blackwell GPUs.
 pub(crate) struct Fsp;
 
-- 
2.53.0
Re: [PATCH v6 23/34] gpu: nova-core: Hopper/Blackwell: add FSP message structures
Posted by Alexandre Courbot 4 weeks, 1 day ago
On Tue Mar 10, 2026 at 11:11 AM JST, John Hubbard wrote:
> Add the NVDM COT payload, FSP message, and FSP response structures
> needed for FSP Chain of Trust communication. Also add FmcSignatures
> to hold the hash, public key, and signature extracted from FMC firmware.
>
> Signed-off-by: John Hubbard <jhubbard@nvidia.com>
> ---
>  drivers/gpu/nova-core/firmware.rs |  5 +-
>  drivers/gpu/nova-core/fsp.rs      | 78 +++++++++++++++++++++++++++++++
>  2 files changed, 82 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs
> index 6a0a02177f6f..be41e07b8448 100644
> --- a/drivers/gpu/nova-core/firmware.rs
> +++ b/drivers/gpu/nova-core/firmware.rs
> @@ -26,6 +26,9 @@
>      },
>  };
>  
> +#[expect(unused)]
> +pub(crate) use elf::elf_section;
> +
>  pub(crate) mod booter;
>  pub(crate) mod fsp;
>  pub(crate) mod fwsec;
> @@ -627,7 +630,7 @@ fn elf32_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> {
>      }
>  
>      /// Automatically detects ELF32 vs ELF64 based on the ELF header.
> -    pub(super) fn elf_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> {
> +    pub(crate) fn elf_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> {
>          // Check ELF magic.
>          if elf.len() < 5 || elf.get(0..4)? != b"\x7fELF" {
>              return None;
> diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs
> index d464ad325881..15731d24d0c5 100644
> --- a/drivers/gpu/nova-core/fsp.rs
> +++ b/drivers/gpu/nova-core/fsp.rs
> @@ -105,6 +105,84 @@ unsafe impl AsBytes for GspFmcBootParams {}
>  // SAFETY: All bit patterns are valid for the primitive fields.
>  unsafe impl FromBytes for GspFmcBootParams {}
>  
> +/// Size constraints for FSP security signatures (Hopper/Blackwell).
> +const FSP_HASH_SIZE: usize = 48; // SHA-384 hash
> +const FSP_PKEY_SIZE: usize = 384; // RSA-3072 public key
> +const FSP_SIG_SIZE: usize = 384; // RSA-3072 signature
> +
> +/// 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],
> +    signature: [u8; FSP_SIG_SIZE],
> +}
> +
> +impl Default for FmcSignatures {
> +    fn default() -> Self {
> +        Self {
> +            hash384: [0u8; FSP_HASH_SIZE],
> +            public_key: [0u8; FSP_PKEY_SIZE],
> +            signature: [0u8; FSP_SIG_SIZE],
> +        }
> +    }
> +}

Since everything is initialized to zero you should be able to derive
`Default` instead of bringing your own implementation.

> +
> +/// FSP Command Response payload structure.
> +/// NVDM_PAYLOAD_COMMAND_RESPONSE structure.
> +#[repr(C, packed)]
> +#[derive(Clone, Copy)]
> +struct NvdmPayloadCommandResponse {
> +    task_id: u32,
> +    command_nvdm_type: u32,
> +    error_code: u32,
> +}
> +
> +/// NVDM (NVIDIA Device Management) COT (Chain of Trust) payload structure.
> +/// This is the main message payload sent to FSP for Chain of Trust.
> +#[repr(C, packed)]
> +#[derive(Clone, Copy)]
> +struct NvdmPayloadCot {
> +    version: u16,
> +    size: u16,
> +    gsp_fmc_sysmem_offset: u64,
> +    frts_sysmem_offset: u64,
> +    frts_sysmem_size: u32,
> +    frts_vidmem_offset: u64,
> +    frts_vidmem_size: u32,
> +    hash384: [u8; FSP_HASH_SIZE],
> +    public_key: [u8; FSP_PKEY_SIZE],
> +    signature: [u8; FSP_SIG_SIZE],
> +    gsp_boot_args_sysmem_offset: u64,
> +}
> +
> +/// Complete FSP message structure with MCTP and NVDM headers.
> +#[repr(C, packed)]
> +#[derive(Clone, Copy)]
> +#[expect(dead_code)]
> +struct FspMessage {
> +    mctp_header: u32,
> +    nvdm_header: u32,
> +    cot: NvdmPayloadCot,
> +}
> +
> +// SAFETY: FspMessage is a packed C struct with only integral fields.
> +unsafe impl AsBytes for FspMessage {}
> +
> +/// Complete FSP response structure with MCTP and NVDM headers.
> +#[repr(C, packed)]
> +#[derive(Clone, Copy)]
> +#[expect(dead_code)]
> +struct FspResponse {
> +    mctp_header: u32,
> +    nvdm_header: u32,
> +    response: NvdmPayloadCommandResponse,
> +}
> +
> +// SAFETY: FspResponse is a packed C struct with only integral fields.
> +unsafe impl FromBytes for FspResponse {}
> +
>  /// FSP interface for Hopper/Blackwell GPUs.
>  pub(crate) struct Fsp;

All this code seems to be directly or indirectly dead for now - is there
a way to merge this patch with the one that makes use of these? I don't
mind larger patches if they mostly add new code, as it comes down to the
same at the end of the day.