1 // SPDX-License-Identifier: GPL-2.0 2 // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 4 //! FSP is a hardware unit that runs FMC firmware. 5 6 use kernel::{ 7 device, 8 dma::Coherent, 9 prelude::*, // 10 }; 11 12 use crate::{ 13 firmware::tlv::{ 14 request_tlv, // 15 Tlv, 16 }, 17 gpu::Chipset, // 18 }; 19 20 /// Size of the FSP SHA-384 hash, in bytes. 21 const FSP_HASH_SIZE: usize = 48; 22 /// Maximum size of the FSP public key (RSA-3072), in bytes. 23 /// 24 /// The FMC `PKEY` tag may be shorter, so the remaining bytes are zero-padded. 25 const FSP_PKEY_SIZE: usize = 384; 26 /// Maximum size of the FSP signature (RSA-3072), in bytes. 27 /// 28 /// The FMC `SIGN` tag may be shorter, so the remaining bytes are zero-padded. 29 const FSP_SIG_SIZE: usize = 384; 30 31 /// Structure to hold FMC signatures. 32 /// 33 /// C representation is used because this type is used for communication with the FSP. 34 #[derive(Debug, Clone, Copy, Zeroable)] 35 #[repr(C)] 36 pub(crate) struct FmcSignatures { 37 pub(crate) hash384: [u8; FSP_HASH_SIZE], 38 pub(crate) public_key: [u8; FSP_PKEY_SIZE], 39 pub(crate) signature: [u8; FSP_SIG_SIZE], 40 } 41 42 pub(crate) struct FspFirmware { 43 /// FMC firmware image data 44 pub(crate) fmc_image: Coherent<[u8]>, 45 /// FMC firmware signatures. 46 pub(crate) fmc_sigs: KBox<FmcSignatures>, 47 } 48 49 impl FspFirmware { 50 pub(crate) fn new(dev: &device::Device<device::Bound>, chipset: Chipset) -> Result<Self> { 51 let fw = request_tlv(dev, chipset, "fmc")?; 52 let tlv = Tlv::new(fw.data())?; 53 dev_dbg!(dev, "loaded fsp firmware v{}\n", tlv.get_string(b"VERS")?); 54 55 let fmc_image_data = tlv.get_bytes(b"BLOB")?; 56 let fmc_image = Coherent::from_slice(dev, fmc_image_data, GFP_KERNEL)?; 57 58 Ok(Self { 59 fmc_image, 60 fmc_sigs: Self::extract_fmc_signatures(&tlv, dev)?, 61 }) 62 } 63 64 /// Extract FMC firmware signatures for Chain of Trust verification. 65 /// 66 /// Extracts real cryptographic signatures from FMC TLV firmware tags. 67 /// Returns signatures in a heap-allocated structure to prevent stack overflow. 68 fn extract_fmc_signatures(tlv: &Tlv<'_>, dev: &device::Device) -> Result<KBox<FmcSignatures>> { 69 let hash_section = tlv.get_bytes(b"HASH")?; 70 let pkey_section = tlv.get_bytes(b"PKEY")?; 71 let sig_section = tlv.get_bytes(b"SIGN")?; 72 73 // The hash section is a SHA-384 output: it must be exactly FSP_HASH_SIZE bytes. 74 if hash_section.len() != FSP_HASH_SIZE { 75 dev_err!( 76 dev, 77 "FMC hash section size {} != expected {}\n", 78 hash_section.len(), 79 FSP_HASH_SIZE 80 ); 81 return Err(EINVAL); 82 } 83 84 // The key and signature sections are zero-padded to a fixed maximum, so they may be 85 // shorter, but must not exceed the destination buffers. 86 if pkey_section.len() > FSP_PKEY_SIZE { 87 dev_err!( 88 dev, 89 "FMC public key section size {} > maximum {}\n", 90 pkey_section.len(), 91 FSP_PKEY_SIZE 92 ); 93 return Err(EINVAL); 94 } 95 if sig_section.len() > FSP_SIG_SIZE { 96 dev_err!( 97 dev, 98 "FMC signature section size {} > maximum {}\n", 99 sig_section.len(), 100 FSP_SIG_SIZE 101 ); 102 return Err(EINVAL); 103 } 104 105 // Initialize the signatures in place to avoid building the large `FmcSignatures` on the 106 // stack, then fill each section from the firmware. 107 let signatures = KBox::init( 108 pin_init::init_zeroed::<FmcSignatures>().chain(|sigs| { 109 // PANIC: src and dst lengths are both FSP_HASH_SIZE (verified above). 110 sigs.hash384.copy_from_slice(hash_section); 111 // PANIC: dst is sliced to src.len(); src.len() <= FSP_PKEY_SIZE (verified above). 112 sigs.public_key[..pkey_section.len()].copy_from_slice(pkey_section); 113 // PANIC: dst is sliced to src.len(); src.len() <= FSP_SIG_SIZE (verified above). 114 sigs.signature[..sig_section.len()].copy_from_slice(sig_section); 115 Ok(()) 116 }), 117 GFP_KERNEL, 118 )?; 119 120 Ok(signatures) 121 } 122 } 123