xref: /linux/drivers/gpu/nova-core/firmware/fwsec.rs (revision 220994d61cebfc04f071d69049127657c7e8191b)
131f0feefSAlexandre Courbot // SPDX-License-Identifier: GPL-2.0
231f0feefSAlexandre Courbot 
331f0feefSAlexandre Courbot //! FWSEC is a High Secure firmware that is extracted from the BIOS and performs the first step of
431f0feefSAlexandre Courbot //! the GSP startup by creating the WPR2 memory region and copying critical areas of the VBIOS into
531f0feefSAlexandre Courbot //! it after authenticating them, ensuring they haven't been tampered with. It runs on the GSP
631f0feefSAlexandre Courbot //! falcon.
731f0feefSAlexandre Courbot //!
831f0feefSAlexandre Courbot //! Before being run, it needs to be patched in two areas:
931f0feefSAlexandre Courbot //!
1031f0feefSAlexandre Courbot //! - The command to be run, as this firmware can perform several tasks ;
1131f0feefSAlexandre Courbot //! - The ucode signature, so the GSP falcon can run FWSEC in HS mode.
1231f0feefSAlexandre Courbot 
1331f0feefSAlexandre Courbot use core::marker::PhantomData;
1431f0feefSAlexandre Courbot use core::mem::{align_of, size_of};
1531f0feefSAlexandre Courbot use core::ops::Deref;
1631f0feefSAlexandre Courbot 
1731f0feefSAlexandre Courbot use kernel::device::{self, Device};
1831f0feefSAlexandre Courbot use kernel::prelude::*;
1931f0feefSAlexandre Courbot use kernel::transmute::FromBytes;
2031f0feefSAlexandre Courbot 
2131f0feefSAlexandre Courbot use crate::dma::DmaObject;
2231f0feefSAlexandre Courbot use crate::driver::Bar0;
2331f0feefSAlexandre Courbot use crate::falcon::gsp::Gsp;
2431f0feefSAlexandre Courbot use crate::falcon::{Falcon, FalconBromParams, FalconFirmware, FalconLoadParams, FalconLoadTarget};
2531f0feefSAlexandre Courbot use crate::firmware::{FalconUCodeDescV3, FirmwareDmaObject, FirmwareSignature, Signed, Unsigned};
2631f0feefSAlexandre Courbot use crate::vbios::Vbios;
2731f0feefSAlexandre Courbot 
2831f0feefSAlexandre Courbot const NVFW_FALCON_APPIF_ID_DMEMMAPPER: u32 = 0x4;
2931f0feefSAlexandre Courbot 
3031f0feefSAlexandre Courbot #[repr(C)]
3131f0feefSAlexandre Courbot #[derive(Debug)]
3231f0feefSAlexandre Courbot struct FalconAppifHdrV1 {
3331f0feefSAlexandre Courbot     version: u8,
3431f0feefSAlexandre Courbot     header_size: u8,
3531f0feefSAlexandre Courbot     entry_size: u8,
3631f0feefSAlexandre Courbot     entry_count: u8,
3731f0feefSAlexandre Courbot }
3831f0feefSAlexandre Courbot // SAFETY: any byte sequence is valid for this struct.
3931f0feefSAlexandre Courbot unsafe impl FromBytes for FalconAppifHdrV1 {}
4031f0feefSAlexandre Courbot 
4131f0feefSAlexandre Courbot #[repr(C, packed)]
4231f0feefSAlexandre Courbot #[derive(Debug)]
4331f0feefSAlexandre Courbot struct FalconAppifV1 {
4431f0feefSAlexandre Courbot     id: u32,
4531f0feefSAlexandre Courbot     dmem_base: u32,
4631f0feefSAlexandre Courbot }
4731f0feefSAlexandre Courbot // SAFETY: any byte sequence is valid for this struct.
4831f0feefSAlexandre Courbot unsafe impl FromBytes for FalconAppifV1 {}
4931f0feefSAlexandre Courbot 
5031f0feefSAlexandre Courbot #[derive(Debug)]
5131f0feefSAlexandre Courbot #[repr(C, packed)]
5231f0feefSAlexandre Courbot struct FalconAppifDmemmapperV3 {
5331f0feefSAlexandre Courbot     signature: u32,
5431f0feefSAlexandre Courbot     version: u16,
5531f0feefSAlexandre Courbot     size: u16,
5631f0feefSAlexandre Courbot     cmd_in_buffer_offset: u32,
5731f0feefSAlexandre Courbot     cmd_in_buffer_size: u32,
5831f0feefSAlexandre Courbot     cmd_out_buffer_offset: u32,
5931f0feefSAlexandre Courbot     cmd_out_buffer_size: u32,
6031f0feefSAlexandre Courbot     nvf_img_data_buffer_offset: u32,
6131f0feefSAlexandre Courbot     nvf_img_data_buffer_size: u32,
6231f0feefSAlexandre Courbot     printf_buffer_hdr: u32,
6331f0feefSAlexandre Courbot     ucode_build_time_stamp: u32,
6431f0feefSAlexandre Courbot     ucode_signature: u32,
6531f0feefSAlexandre Courbot     init_cmd: u32,
6631f0feefSAlexandre Courbot     ucode_feature: u32,
6731f0feefSAlexandre Courbot     ucode_cmd_mask0: u32,
6831f0feefSAlexandre Courbot     ucode_cmd_mask1: u32,
6931f0feefSAlexandre Courbot     multi_tgt_tbl: u32,
7031f0feefSAlexandre Courbot }
7131f0feefSAlexandre Courbot // SAFETY: any byte sequence is valid for this struct.
7231f0feefSAlexandre Courbot unsafe impl FromBytes for FalconAppifDmemmapperV3 {}
7331f0feefSAlexandre Courbot 
7431f0feefSAlexandre Courbot #[derive(Debug)]
7531f0feefSAlexandre Courbot #[repr(C, packed)]
7631f0feefSAlexandre Courbot struct ReadVbios {
7731f0feefSAlexandre Courbot     ver: u32,
7831f0feefSAlexandre Courbot     hdr: u32,
7931f0feefSAlexandre Courbot     addr: u64,
8031f0feefSAlexandre Courbot     size: u32,
8131f0feefSAlexandre Courbot     flags: u32,
8231f0feefSAlexandre Courbot }
8331f0feefSAlexandre Courbot // SAFETY: any byte sequence is valid for this struct.
8431f0feefSAlexandre Courbot unsafe impl FromBytes for ReadVbios {}
8531f0feefSAlexandre Courbot 
8631f0feefSAlexandre Courbot #[derive(Debug)]
8731f0feefSAlexandre Courbot #[repr(C, packed)]
8831f0feefSAlexandre Courbot struct FrtsRegion {
8931f0feefSAlexandre Courbot     ver: u32,
9031f0feefSAlexandre Courbot     hdr: u32,
9131f0feefSAlexandre Courbot     addr: u32,
9231f0feefSAlexandre Courbot     size: u32,
9331f0feefSAlexandre Courbot     ftype: u32,
9431f0feefSAlexandre Courbot }
9531f0feefSAlexandre Courbot // SAFETY: any byte sequence is valid for this struct.
9631f0feefSAlexandre Courbot unsafe impl FromBytes for FrtsRegion {}
9731f0feefSAlexandre Courbot 
9831f0feefSAlexandre Courbot const NVFW_FRTS_CMD_REGION_TYPE_FB: u32 = 2;
9931f0feefSAlexandre Courbot 
10031f0feefSAlexandre Courbot #[repr(C, packed)]
10131f0feefSAlexandre Courbot struct FrtsCmd {
10231f0feefSAlexandre Courbot     read_vbios: ReadVbios,
10331f0feefSAlexandre Courbot     frts_region: FrtsRegion,
10431f0feefSAlexandre Courbot }
10531f0feefSAlexandre Courbot // SAFETY: any byte sequence is valid for this struct.
10631f0feefSAlexandre Courbot unsafe impl FromBytes for FrtsCmd {}
10731f0feefSAlexandre Courbot 
10831f0feefSAlexandre Courbot const NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS: u32 = 0x15;
10931f0feefSAlexandre Courbot const NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB: u32 = 0x19;
11031f0feefSAlexandre Courbot 
11131f0feefSAlexandre Courbot /// Command for the [`FwsecFirmware`] to execute.
11231f0feefSAlexandre Courbot pub(crate) enum FwsecCommand {
11331f0feefSAlexandre Courbot     /// Asks [`FwsecFirmware`] to carve out the WPR2 area and place a verified copy of the VBIOS
11431f0feefSAlexandre Courbot     /// image into it.
11531f0feefSAlexandre Courbot     Frts { frts_addr: u64, frts_size: u64 },
11631f0feefSAlexandre Courbot     /// Asks [`FwsecFirmware`] to load pre-OS apps on the PMU.
11731f0feefSAlexandre Courbot     #[expect(dead_code)]
11831f0feefSAlexandre Courbot     Sb,
11931f0feefSAlexandre Courbot }
12031f0feefSAlexandre Courbot 
12131f0feefSAlexandre Courbot /// Size of the signatures used in FWSEC.
12231f0feefSAlexandre Courbot const BCRT30_RSA3K_SIG_SIZE: usize = 384;
12331f0feefSAlexandre Courbot 
12431f0feefSAlexandre Courbot /// A single signature that can be patched into a FWSEC image.
12531f0feefSAlexandre Courbot #[repr(transparent)]
12631f0feefSAlexandre Courbot pub(crate) struct Bcrt30Rsa3kSignature([u8; BCRT30_RSA3K_SIG_SIZE]);
12731f0feefSAlexandre Courbot 
12831f0feefSAlexandre Courbot /// SAFETY: A signature is just an array of bytes.
12931f0feefSAlexandre Courbot unsafe impl FromBytes for Bcrt30Rsa3kSignature {}
13031f0feefSAlexandre Courbot 
13131f0feefSAlexandre Courbot impl From<[u8; BCRT30_RSA3K_SIG_SIZE]> for Bcrt30Rsa3kSignature {
from(sig: [u8; BCRT30_RSA3K_SIG_SIZE]) -> Self13231f0feefSAlexandre Courbot     fn from(sig: [u8; BCRT30_RSA3K_SIG_SIZE]) -> Self {
13331f0feefSAlexandre Courbot         Self(sig)
13431f0feefSAlexandre Courbot     }
13531f0feefSAlexandre Courbot }
13631f0feefSAlexandre Courbot 
13731f0feefSAlexandre Courbot impl AsRef<[u8]> for Bcrt30Rsa3kSignature {
as_ref(&self) -> &[u8]13831f0feefSAlexandre Courbot     fn as_ref(&self) -> &[u8] {
13931f0feefSAlexandre Courbot         &self.0
14031f0feefSAlexandre Courbot     }
14131f0feefSAlexandre Courbot }
14231f0feefSAlexandre Courbot 
14331f0feefSAlexandre Courbot impl FirmwareSignature<FwsecFirmware> for Bcrt30Rsa3kSignature {}
14431f0feefSAlexandre Courbot 
14531f0feefSAlexandre Courbot /// Reinterpret the area starting from `offset` in `fw` as an instance of `T` (which must implement
14631f0feefSAlexandre Courbot /// [`FromBytes`]) and return a reference to it.
14731f0feefSAlexandre Courbot ///
14831f0feefSAlexandre Courbot /// # Safety
14931f0feefSAlexandre Courbot ///
15031f0feefSAlexandre Courbot /// Callers must ensure that the region of memory returned is not written for as long as the
15131f0feefSAlexandre Courbot /// returned reference is alive.
15231f0feefSAlexandre Courbot ///
1533606620bSAlexandre Courbot /// TODO[TRSM][COHA]: Remove this and `transmute_mut` once `CoherentAllocation::as_slice` is
1543606620bSAlexandre Courbot /// available and we have a way to transmute objects implementing FromBytes, e.g.:
15531f0feefSAlexandre Courbot /// https://lore.kernel.org/lkml/20250330234039.29814-1-christiansantoslima21@gmail.com/
transmute<'a, 'b, T: Sized + FromBytes>( fw: &'a DmaObject, offset: usize, ) -> Result<&'b T>15631f0feefSAlexandre Courbot unsafe fn transmute<'a, 'b, T: Sized + FromBytes>(
15731f0feefSAlexandre Courbot     fw: &'a DmaObject,
15831f0feefSAlexandre Courbot     offset: usize,
15931f0feefSAlexandre Courbot ) -> Result<&'b T> {
16031f0feefSAlexandre Courbot     if offset + size_of::<T>() > fw.size() {
16131f0feefSAlexandre Courbot         return Err(EINVAL);
16231f0feefSAlexandre Courbot     }
16331f0feefSAlexandre Courbot     if (fw.start_ptr() as usize + offset) % align_of::<T>() != 0 {
16431f0feefSAlexandre Courbot         return Err(EINVAL);
16531f0feefSAlexandre Courbot     }
16631f0feefSAlexandre Courbot 
16731f0feefSAlexandre Courbot     // SAFETY: we have checked that the pointer is properly aligned that its pointed memory is
16831f0feefSAlexandre Courbot     // large enough the contains an instance of `T`, which implements `FromBytes`.
16931f0feefSAlexandre Courbot     Ok(unsafe { &*(fw.start_ptr().add(offset).cast::<T>()) })
17031f0feefSAlexandre Courbot }
17131f0feefSAlexandre Courbot 
17231f0feefSAlexandre Courbot /// Reinterpret the area starting from `offset` in `fw` as a mutable instance of `T` (which must
17331f0feefSAlexandre Courbot /// implement [`FromBytes`]) and return a reference to it.
17431f0feefSAlexandre Courbot ///
17531f0feefSAlexandre Courbot /// # Safety
17631f0feefSAlexandre Courbot ///
17731f0feefSAlexandre Courbot /// Callers must ensure that the region of memory returned is not read or written for as long as
17831f0feefSAlexandre Courbot /// the returned reference is alive.
transmute_mut<'a, 'b, T: Sized + FromBytes>( fw: &'a mut DmaObject, offset: usize, ) -> Result<&'b mut T>17931f0feefSAlexandre Courbot unsafe fn transmute_mut<'a, 'b, T: Sized + FromBytes>(
18031f0feefSAlexandre Courbot     fw: &'a mut DmaObject,
18131f0feefSAlexandre Courbot     offset: usize,
18231f0feefSAlexandre Courbot ) -> Result<&'b mut T> {
18331f0feefSAlexandre Courbot     if offset + size_of::<T>() > fw.size() {
18431f0feefSAlexandre Courbot         return Err(EINVAL);
18531f0feefSAlexandre Courbot     }
18631f0feefSAlexandre Courbot     if (fw.start_ptr_mut() as usize + offset) % align_of::<T>() != 0 {
18731f0feefSAlexandre Courbot         return Err(EINVAL);
18831f0feefSAlexandre Courbot     }
18931f0feefSAlexandre Courbot 
19031f0feefSAlexandre Courbot     // SAFETY: we have checked that the pointer is properly aligned that its pointed memory is
19131f0feefSAlexandre Courbot     // large enough the contains an instance of `T`, which implements `FromBytes`.
19231f0feefSAlexandre Courbot     Ok(unsafe { &mut *(fw.start_ptr_mut().add(offset).cast::<T>()) })
19331f0feefSAlexandre Courbot }
19431f0feefSAlexandre Courbot 
19531f0feefSAlexandre Courbot /// The FWSEC microcode, extracted from the BIOS and to be run on the GSP falcon.
19631f0feefSAlexandre Courbot ///
19731f0feefSAlexandre Courbot /// It is responsible for e.g. carving out the WPR2 region as the first step of the GSP bootflow.
19831f0feefSAlexandre Courbot pub(crate) struct FwsecFirmware {
19931f0feefSAlexandre Courbot     /// Descriptor of the firmware.
20031f0feefSAlexandre Courbot     desc: FalconUCodeDescV3,
20131f0feefSAlexandre Courbot     /// GPU-accessible DMA object containing the firmware.
20231f0feefSAlexandre Courbot     ucode: FirmwareDmaObject<Self, Signed>,
20331f0feefSAlexandre Courbot }
20431f0feefSAlexandre Courbot 
20531f0feefSAlexandre Courbot // We need to load full DMEM pages.
20631f0feefSAlexandre Courbot const DMEM_LOAD_SIZE_ALIGN: u32 = 256;
20731f0feefSAlexandre Courbot 
20831f0feefSAlexandre Courbot impl FalconLoadParams for FwsecFirmware {
imem_load_params(&self) -> FalconLoadTarget20931f0feefSAlexandre Courbot     fn imem_load_params(&self) -> FalconLoadTarget {
21031f0feefSAlexandre Courbot         FalconLoadTarget {
21131f0feefSAlexandre Courbot             src_start: 0,
21231f0feefSAlexandre Courbot             dst_start: self.desc.imem_phys_base,
21331f0feefSAlexandre Courbot             len: self.desc.imem_load_size,
21431f0feefSAlexandre Courbot         }
21531f0feefSAlexandre Courbot     }
21631f0feefSAlexandre Courbot 
dmem_load_params(&self) -> FalconLoadTarget21731f0feefSAlexandre Courbot     fn dmem_load_params(&self) -> FalconLoadTarget {
21831f0feefSAlexandre Courbot         FalconLoadTarget {
21931f0feefSAlexandre Courbot             src_start: self.desc.imem_load_size,
22031f0feefSAlexandre Courbot             dst_start: self.desc.dmem_phys_base,
2213606620bSAlexandre Courbot             // TODO[NUMM]: replace with `align_up` once it lands.
22231f0feefSAlexandre Courbot             len: self
22331f0feefSAlexandre Courbot                 .desc
22431f0feefSAlexandre Courbot                 .dmem_load_size
22531f0feefSAlexandre Courbot                 .next_multiple_of(DMEM_LOAD_SIZE_ALIGN),
22631f0feefSAlexandre Courbot         }
22731f0feefSAlexandre Courbot     }
22831f0feefSAlexandre Courbot 
brom_params(&self) -> FalconBromParams22931f0feefSAlexandre Courbot     fn brom_params(&self) -> FalconBromParams {
23031f0feefSAlexandre Courbot         FalconBromParams {
23131f0feefSAlexandre Courbot             pkc_data_offset: self.desc.pkc_data_offset,
23231f0feefSAlexandre Courbot             engine_id_mask: self.desc.engine_id_mask,
23331f0feefSAlexandre Courbot             ucode_id: self.desc.ucode_id,
23431f0feefSAlexandre Courbot         }
23531f0feefSAlexandre Courbot     }
23631f0feefSAlexandre Courbot 
boot_addr(&self) -> u3223731f0feefSAlexandre Courbot     fn boot_addr(&self) -> u32 {
23831f0feefSAlexandre Courbot         0
23931f0feefSAlexandre Courbot     }
24031f0feefSAlexandre Courbot }
24131f0feefSAlexandre Courbot 
24231f0feefSAlexandre Courbot impl Deref for FwsecFirmware {
24331f0feefSAlexandre Courbot     type Target = DmaObject;
24431f0feefSAlexandre Courbot 
deref(&self) -> &Self::Target24531f0feefSAlexandre Courbot     fn deref(&self) -> &Self::Target {
24631f0feefSAlexandre Courbot         &self.ucode.0
24731f0feefSAlexandre Courbot     }
24831f0feefSAlexandre Courbot }
24931f0feefSAlexandre Courbot 
25031f0feefSAlexandre Courbot impl FalconFirmware for FwsecFirmware {
25131f0feefSAlexandre Courbot     type Target = Gsp;
25231f0feefSAlexandre Courbot }
25331f0feefSAlexandre Courbot 
25431f0feefSAlexandre Courbot impl FirmwareDmaObject<FwsecFirmware, Unsigned> {
new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Result<Self>25531f0feefSAlexandre Courbot     fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Result<Self> {
25631f0feefSAlexandre Courbot         let desc = bios.fwsec_image().header(dev)?;
25731f0feefSAlexandre Courbot         let ucode = bios.fwsec_image().ucode(dev, desc)?;
25831f0feefSAlexandre Courbot         let mut dma_object = DmaObject::from_data(dev, ucode)?;
25931f0feefSAlexandre Courbot 
26031f0feefSAlexandre Courbot         let hdr_offset = (desc.imem_load_size + desc.interface_offset) as usize;
26131f0feefSAlexandre Courbot         // SAFETY: we have exclusive access to `dma_object`.
26231f0feefSAlexandre Courbot         let hdr: &FalconAppifHdrV1 = unsafe { transmute(&dma_object, hdr_offset) }?;
26331f0feefSAlexandre Courbot 
26431f0feefSAlexandre Courbot         if hdr.version != 1 {
26531f0feefSAlexandre Courbot             return Err(EINVAL);
26631f0feefSAlexandre Courbot         }
26731f0feefSAlexandre Courbot 
26831f0feefSAlexandre Courbot         // Find the DMEM mapper section in the firmware.
26931f0feefSAlexandre Courbot         for i in 0..hdr.entry_count as usize {
27031f0feefSAlexandre Courbot             let app: &FalconAppifV1 =
27131f0feefSAlexandre Courbot             // SAFETY: we have exclusive access to `dma_object`.
27231f0feefSAlexandre Courbot             unsafe {
27331f0feefSAlexandre Courbot                 transmute(
27431f0feefSAlexandre Courbot                     &dma_object,
27531f0feefSAlexandre Courbot                     hdr_offset + hdr.header_size as usize + i * hdr.entry_size as usize
27631f0feefSAlexandre Courbot                 )
27731f0feefSAlexandre Courbot             }?;
27831f0feefSAlexandre Courbot 
27931f0feefSAlexandre Courbot             if app.id != NVFW_FALCON_APPIF_ID_DMEMMAPPER {
28031f0feefSAlexandre Courbot                 continue;
28131f0feefSAlexandre Courbot             }
28231f0feefSAlexandre Courbot 
28331f0feefSAlexandre Courbot             // SAFETY: we have exclusive access to `dma_object`.
28431f0feefSAlexandre Courbot             let dmem_mapper: &mut FalconAppifDmemmapperV3 = unsafe {
28531f0feefSAlexandre Courbot                 transmute_mut(
28631f0feefSAlexandre Courbot                     &mut dma_object,
28731f0feefSAlexandre Courbot                     (desc.imem_load_size + app.dmem_base) as usize,
28831f0feefSAlexandre Courbot                 )
28931f0feefSAlexandre Courbot             }?;
29031f0feefSAlexandre Courbot 
29131f0feefSAlexandre Courbot             // SAFETY: we have exclusive access to `dma_object`.
29231f0feefSAlexandre Courbot             let frts_cmd: &mut FrtsCmd = unsafe {
29331f0feefSAlexandre Courbot                 transmute_mut(
29431f0feefSAlexandre Courbot                     &mut dma_object,
29531f0feefSAlexandre Courbot                     (desc.imem_load_size + dmem_mapper.cmd_in_buffer_offset) as usize,
29631f0feefSAlexandre Courbot                 )
29731f0feefSAlexandre Courbot             }?;
29831f0feefSAlexandre Courbot 
29931f0feefSAlexandre Courbot             frts_cmd.read_vbios = ReadVbios {
30031f0feefSAlexandre Courbot                 ver: 1,
30131f0feefSAlexandre Courbot                 hdr: size_of::<ReadVbios>() as u32,
30231f0feefSAlexandre Courbot                 addr: 0,
30331f0feefSAlexandre Courbot                 size: 0,
30431f0feefSAlexandre Courbot                 flags: 2,
30531f0feefSAlexandre Courbot             };
30631f0feefSAlexandre Courbot 
30731f0feefSAlexandre Courbot             dmem_mapper.init_cmd = match cmd {
30831f0feefSAlexandre Courbot                 FwsecCommand::Frts {
30931f0feefSAlexandre Courbot                     frts_addr,
31031f0feefSAlexandre Courbot                     frts_size,
31131f0feefSAlexandre Courbot                 } => {
31231f0feefSAlexandre Courbot                     frts_cmd.frts_region = FrtsRegion {
31331f0feefSAlexandre Courbot                         ver: 1,
31431f0feefSAlexandre Courbot                         hdr: size_of::<FrtsRegion>() as u32,
31531f0feefSAlexandre Courbot                         addr: (frts_addr >> 12) as u32,
31631f0feefSAlexandre Courbot                         size: (frts_size >> 12) as u32,
31731f0feefSAlexandre Courbot                         ftype: NVFW_FRTS_CMD_REGION_TYPE_FB,
31831f0feefSAlexandre Courbot                     };
31931f0feefSAlexandre Courbot 
32031f0feefSAlexandre Courbot                     NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS
32131f0feefSAlexandre Courbot                 }
32231f0feefSAlexandre Courbot                 FwsecCommand::Sb => NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB,
32331f0feefSAlexandre Courbot             };
32431f0feefSAlexandre Courbot 
32531f0feefSAlexandre Courbot             // Return early as we found and patched the DMEMMAPPER region.
32631f0feefSAlexandre Courbot             return Ok(Self(dma_object, PhantomData));
32731f0feefSAlexandre Courbot         }
32831f0feefSAlexandre Courbot 
32931f0feefSAlexandre Courbot         Err(ENOTSUPP)
33031f0feefSAlexandre Courbot     }
33131f0feefSAlexandre Courbot }
33231f0feefSAlexandre Courbot 
33331f0feefSAlexandre Courbot impl FwsecFirmware {
33431f0feefSAlexandre Courbot     /// Extract the Fwsec firmware from `bios` and patch it to run on `falcon` with the `cmd`
33531f0feefSAlexandre Courbot     /// command.
new( dev: &Device<device::Bound>, falcon: &Falcon<Gsp>, bar: &Bar0, bios: &Vbios, cmd: FwsecCommand, ) -> Result<Self>33631f0feefSAlexandre Courbot     pub(crate) fn new(
33731f0feefSAlexandre Courbot         dev: &Device<device::Bound>,
33831f0feefSAlexandre Courbot         falcon: &Falcon<Gsp>,
33931f0feefSAlexandre Courbot         bar: &Bar0,
34031f0feefSAlexandre Courbot         bios: &Vbios,
34131f0feefSAlexandre Courbot         cmd: FwsecCommand,
34231f0feefSAlexandre Courbot     ) -> Result<Self> {
34331f0feefSAlexandre Courbot         let ucode_dma = FirmwareDmaObject::<Self, _>::new_fwsec(dev, bios, cmd)?;
34431f0feefSAlexandre Courbot 
34531f0feefSAlexandre Courbot         // Patch signature if needed.
34631f0feefSAlexandre Courbot         let desc = bios.fwsec_image().header(dev)?;
34731f0feefSAlexandre Courbot         let ucode_signed = if desc.signature_count != 0 {
34831f0feefSAlexandre Courbot             let sig_base_img = (desc.imem_load_size + desc.pkc_data_offset) as usize;
349*43ad65ecSDanilo Krummrich             let desc_sig_versions = u32::from(desc.signature_versions);
35031f0feefSAlexandre Courbot             let reg_fuse_version =
35131f0feefSAlexandre Courbot                 falcon.signature_reg_fuse_version(bar, desc.engine_id_mask, desc.ucode_id)?;
35231f0feefSAlexandre Courbot             dev_dbg!(
35331f0feefSAlexandre Courbot                 dev,
35431f0feefSAlexandre Courbot                 "desc_sig_versions: {:#x}, reg_fuse_version: {}\n",
35531f0feefSAlexandre Courbot                 desc_sig_versions,
35631f0feefSAlexandre Courbot                 reg_fuse_version
35731f0feefSAlexandre Courbot             );
35831f0feefSAlexandre Courbot             let signature_idx = {
35931f0feefSAlexandre Courbot                 let reg_fuse_version_bit = 1 << reg_fuse_version;
36031f0feefSAlexandre Courbot 
36131f0feefSAlexandre Courbot                 // Check if the fuse version is supported by the firmware.
36231f0feefSAlexandre Courbot                 if desc_sig_versions & reg_fuse_version_bit == 0 {
36331f0feefSAlexandre Courbot                     dev_err!(
36431f0feefSAlexandre Courbot                         dev,
36531f0feefSAlexandre Courbot                         "no matching signature: {:#x} {:#x}\n",
36631f0feefSAlexandre Courbot                         reg_fuse_version_bit,
36731f0feefSAlexandre Courbot                         desc_sig_versions,
36831f0feefSAlexandre Courbot                     );
36931f0feefSAlexandre Courbot                     return Err(EINVAL);
37031f0feefSAlexandre Courbot                 }
37131f0feefSAlexandre Courbot 
37231f0feefSAlexandre Courbot                 // `desc_sig_versions` has one bit set per included signature. Thus, the index of
37331f0feefSAlexandre Courbot                 // the signature to patch is the number of bits in `desc_sig_versions` set to `1`
37431f0feefSAlexandre Courbot                 // before `reg_fuse_version_bit`.
37531f0feefSAlexandre Courbot 
37631f0feefSAlexandre Courbot                 // Mask of the bits of `desc_sig_versions` to preserve.
37731f0feefSAlexandre Courbot                 let reg_fuse_version_mask = reg_fuse_version_bit.wrapping_sub(1);
37831f0feefSAlexandre Courbot 
37931f0feefSAlexandre Courbot                 (desc_sig_versions & reg_fuse_version_mask).count_ones() as usize
38031f0feefSAlexandre Courbot             };
38131f0feefSAlexandre Courbot 
38231f0feefSAlexandre Courbot             dev_dbg!(dev, "patching signature with index {}\n", signature_idx);
38331f0feefSAlexandre Courbot             let signature = bios
38431f0feefSAlexandre Courbot                 .fwsec_image()
38531f0feefSAlexandre Courbot                 .sigs(dev, desc)
38631f0feefSAlexandre Courbot                 .and_then(|sigs| sigs.get(signature_idx).ok_or(EINVAL))?;
38731f0feefSAlexandre Courbot 
38831f0feefSAlexandre Courbot             ucode_dma.patch_signature(signature, sig_base_img)?
38931f0feefSAlexandre Courbot         } else {
39031f0feefSAlexandre Courbot             ucode_dma.no_patch_signature()
39131f0feefSAlexandre Courbot         };
39231f0feefSAlexandre Courbot 
39331f0feefSAlexandre Courbot         Ok(FwsecFirmware {
39431f0feefSAlexandre Courbot             desc: desc.clone(),
39531f0feefSAlexandre Courbot             ucode: ucode_signed,
39631f0feefSAlexandre Courbot         })
39731f0feefSAlexandre Courbot     }
398859aa3d9SAlexandre Courbot 
399859aa3d9SAlexandre Courbot     /// Loads the FWSEC firmware into `falcon` and execute it.
run( &self, dev: &Device<device::Bound>, falcon: &Falcon<Gsp>, bar: &Bar0, ) -> Result<()>400859aa3d9SAlexandre Courbot     pub(crate) fn run(
401859aa3d9SAlexandre Courbot         &self,
402859aa3d9SAlexandre Courbot         dev: &Device<device::Bound>,
403859aa3d9SAlexandre Courbot         falcon: &Falcon<Gsp>,
404859aa3d9SAlexandre Courbot         bar: &Bar0,
405859aa3d9SAlexandre Courbot     ) -> Result<()> {
406859aa3d9SAlexandre Courbot         // Reset falcon, load the firmware, and run it.
407859aa3d9SAlexandre Courbot         falcon
408859aa3d9SAlexandre Courbot             .reset(bar)
409859aa3d9SAlexandre Courbot             .inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
410859aa3d9SAlexandre Courbot         falcon
411859aa3d9SAlexandre Courbot             .dma_load(bar, self)
412859aa3d9SAlexandre Courbot             .inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?;
413859aa3d9SAlexandre Courbot         let (mbox0, _) = falcon
414859aa3d9SAlexandre Courbot             .boot(bar, Some(0), None)
415859aa3d9SAlexandre Courbot             .inspect_err(|e| dev_err!(dev, "Failed to boot FWSEC firmware: {:?}\n", e))?;
416859aa3d9SAlexandre Courbot         if mbox0 != 0 {
417859aa3d9SAlexandre Courbot             dev_err!(dev, "FWSEC firmware returned error {}\n", mbox0);
418859aa3d9SAlexandre Courbot             Err(EIO)
419859aa3d9SAlexandre Courbot         } else {
420859aa3d9SAlexandre Courbot             Ok(())
421859aa3d9SAlexandre Courbot         }
422859aa3d9SAlexandre Courbot     }
42331f0feefSAlexandre Courbot }
424