xref: /linux/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs (revision 4a57e0913e8c7fff407e97909f4ae48caa84d612)
150b3e0c7STimur Tabi // SPDX-License-Identifier: GPL-2.0
250b3e0c7STimur Tabi 
350b3e0c7STimur Tabi //! Bootloader support for the FWSEC firmware.
450b3e0c7STimur Tabi //!
550b3e0c7STimur Tabi //! On Turing, the FWSEC firmware is not loaded directly, but is instead loaded through a small
650b3e0c7STimur Tabi //! bootloader program that performs the required DMA operations. This bootloader itself needs to
750b3e0c7STimur Tabi //! be loaded using PIO.
850b3e0c7STimur Tabi 
950b3e0c7STimur Tabi use kernel::{
1050b3e0c7STimur Tabi     alloc::KVec,
1150b3e0c7STimur Tabi     device::{
1250b3e0c7STimur Tabi         self,
1350b3e0c7STimur Tabi         Device, //
1450b3e0c7STimur Tabi     },
15*1f9283afSAlexandre Courbot     dma::Coherent,
1638f7e545SAlexandre Courbot     io::{
1738f7e545SAlexandre Courbot         register::WithBase, //
1838f7e545SAlexandre Courbot         Io,
1938f7e545SAlexandre Courbot     },
2050b3e0c7STimur Tabi     prelude::*,
2150b3e0c7STimur Tabi     ptr::{
2250b3e0c7STimur Tabi         Alignable,
2350b3e0c7STimur Tabi         Alignment, //
2450b3e0c7STimur Tabi     },
2550b3e0c7STimur Tabi     sizes,
2650b3e0c7STimur Tabi     transmute::{
2750b3e0c7STimur Tabi         AsBytes,
2850b3e0c7STimur Tabi         FromBytes, //
2950b3e0c7STimur Tabi     },
3050b3e0c7STimur Tabi };
3150b3e0c7STimur Tabi 
3250b3e0c7STimur Tabi use crate::{
3350b3e0c7STimur Tabi     driver::Bar0,
3450b3e0c7STimur Tabi     falcon::{
3550b3e0c7STimur Tabi         self,
3650b3e0c7STimur Tabi         gsp::Gsp,
3750b3e0c7STimur Tabi         Falcon,
3850b3e0c7STimur Tabi         FalconBromParams,
3950b3e0c7STimur Tabi         FalconDmaLoadable,
4050b3e0c7STimur Tabi         FalconFbifMemType,
4150b3e0c7STimur Tabi         FalconFbifTarget,
4250b3e0c7STimur Tabi         FalconFirmware,
4350b3e0c7STimur Tabi         FalconPioDmemLoadTarget,
4450b3e0c7STimur Tabi         FalconPioImemLoadTarget,
4550b3e0c7STimur Tabi         FalconPioLoadable, //
4650b3e0c7STimur Tabi     },
4750b3e0c7STimur Tabi     firmware::{
4850b3e0c7STimur Tabi         fwsec::FwsecFirmware,
4950b3e0c7STimur Tabi         request_firmware,
5050b3e0c7STimur Tabi         BinHdr,
5150b3e0c7STimur Tabi         FIRMWARE_VERSION, //
5250b3e0c7STimur Tabi     },
5350b3e0c7STimur Tabi     gpu::Chipset,
5450b3e0c7STimur Tabi     num::FromSafeCast,
5550b3e0c7STimur Tabi     regs,
5650b3e0c7STimur Tabi };
5750b3e0c7STimur Tabi 
5850b3e0c7STimur Tabi /// Descriptor used by RM to figure out the requirements of the boot loader.
5950b3e0c7STimur Tabi ///
6050b3e0c7STimur Tabi /// Most of its fields appear to be legacy and carry incorrect values, so they are left unused.
6150b3e0c7STimur Tabi #[repr(C)]
6250b3e0c7STimur Tabi #[derive(Debug, Clone)]
6350b3e0c7STimur Tabi struct BootloaderDesc {
6450b3e0c7STimur Tabi     /// Starting tag of bootloader.
6550b3e0c7STimur Tabi     start_tag: u32,
6650b3e0c7STimur Tabi     /// DMEM load offset - unused here as we always load at offset `0`.
6750b3e0c7STimur Tabi     _dmem_load_off: u32,
6850b3e0c7STimur Tabi     /// Offset of code section in the image. Unused as there is only one section in the bootloader
6950b3e0c7STimur Tabi     /// binary.
7050b3e0c7STimur Tabi     _code_off: u32,
7150b3e0c7STimur Tabi     /// Size of code section in the image.
7250b3e0c7STimur Tabi     code_size: u32,
7350b3e0c7STimur Tabi     /// Offset of data section in the image. Unused as we build the data section ourselves.
7450b3e0c7STimur Tabi     _data_off: u32,
7550b3e0c7STimur Tabi     /// Size of data section in the image. Unused as we build the data section ourselves.
7650b3e0c7STimur Tabi     _data_size: u32,
7750b3e0c7STimur Tabi }
7850b3e0c7STimur Tabi // SAFETY: any byte sequence is valid for this struct.
7950b3e0c7STimur Tabi unsafe impl FromBytes for BootloaderDesc {}
8050b3e0c7STimur Tabi 
8150b3e0c7STimur Tabi /// Structure used by the boot-loader to load the rest of the code.
8250b3e0c7STimur Tabi ///
8350b3e0c7STimur Tabi /// This has to be filled by the GPU driver and copied into DMEM at offset
8450b3e0c7STimur Tabi /// [`BootloaderDesc.dmem_load_off`].
8550b3e0c7STimur Tabi #[repr(C, packed)]
8650b3e0c7STimur Tabi #[derive(Debug, Clone)]
8750b3e0c7STimur Tabi struct BootloaderDmemDescV2 {
8850b3e0c7STimur Tabi     /// Reserved, should always be first element.
8950b3e0c7STimur Tabi     reserved: [u32; 4],
9050b3e0c7STimur Tabi     /// 16B signature for secure code, 0s if no secure code.
9150b3e0c7STimur Tabi     signature: [u32; 4],
9250b3e0c7STimur Tabi     /// DMA context used by the bootloader while loading code/data.
9350b3e0c7STimur Tabi     ctx_dma: u32,
9450b3e0c7STimur Tabi     /// 256B-aligned physical FB address where code is located.
9550b3e0c7STimur Tabi     code_dma_base: u64,
9650b3e0c7STimur Tabi     /// Offset from `code_dma_base` where the non-secure code is located.
9750b3e0c7STimur Tabi     ///
9850b3e0c7STimur Tabi     /// Also used as destination IMEM offset of non-secure code as the DMA firmware object is
9950b3e0c7STimur Tabi     /// expected to be a mirror image of its loaded state.
10050b3e0c7STimur Tabi     ///
10150b3e0c7STimur Tabi     /// Must be multiple of 256.
10250b3e0c7STimur Tabi     non_sec_code_off: u32,
10350b3e0c7STimur Tabi     /// Size of the non-secure code part.
10450b3e0c7STimur Tabi     non_sec_code_size: u32,
10550b3e0c7STimur Tabi     /// Offset from `code_dma_base` where the secure code is located (must be multiple of 256).
10650b3e0c7STimur Tabi     ///
10750b3e0c7STimur Tabi     /// Also used as destination IMEM offset of secure code as the DMA firmware object is expected
10850b3e0c7STimur Tabi     /// to be a mirror image of its loaded state.
10950b3e0c7STimur Tabi     ///
11050b3e0c7STimur Tabi     /// Must be multiple of 256.
11150b3e0c7STimur Tabi     sec_code_off: u32,
11250b3e0c7STimur Tabi     /// Size of the secure code part.
11350b3e0c7STimur Tabi     sec_code_size: u32,
11450b3e0c7STimur Tabi     /// Code entry point invoked by the bootloader after code is loaded.
11550b3e0c7STimur Tabi     code_entry_point: u32,
11650b3e0c7STimur Tabi     /// 256B-aligned physical FB address where data is located.
11750b3e0c7STimur Tabi     data_dma_base: u64,
11850b3e0c7STimur Tabi     /// Size of data block (should be multiple of 256B).
11950b3e0c7STimur Tabi     data_size: u32,
12050b3e0c7STimur Tabi     /// Number of arguments to be passed to the target firmware being loaded.
12150b3e0c7STimur Tabi     argc: u32,
12250b3e0c7STimur Tabi     /// Arguments to be passed to the target firmware being loaded.
12350b3e0c7STimur Tabi     argv: u32,
12450b3e0c7STimur Tabi }
12550b3e0c7STimur Tabi // SAFETY: This struct doesn't contain uninitialized bytes and doesn't have interior mutability.
12650b3e0c7STimur Tabi unsafe impl AsBytes for BootloaderDmemDescV2 {}
12750b3e0c7STimur Tabi 
12850b3e0c7STimur Tabi /// Wrapper for [`FwsecFirmware`] that includes the bootloader performing the actual load
12950b3e0c7STimur Tabi /// operation.
13050b3e0c7STimur Tabi pub(crate) struct FwsecFirmwareWithBl {
13150b3e0c7STimur Tabi     /// DMA object the bootloader will copy the firmware from.
132*1f9283afSAlexandre Courbot     _firmware_dma: Coherent<[u8]>,
13350b3e0c7STimur Tabi     /// Code of the bootloader to be loaded into non-secure IMEM.
13450b3e0c7STimur Tabi     ucode: KVec<u8>,
13550b3e0c7STimur Tabi     /// Descriptor to be loaded into DMEM for the bootloader to read.
13650b3e0c7STimur Tabi     dmem_desc: BootloaderDmemDescV2,
13750b3e0c7STimur Tabi     /// Range-validated start offset of the firmware code in IMEM.
13850b3e0c7STimur Tabi     imem_dst_start: u16,
13950b3e0c7STimur Tabi     /// BROM parameters of the loaded firmware.
14050b3e0c7STimur Tabi     brom_params: FalconBromParams,
14150b3e0c7STimur Tabi     /// Range-validated `desc.start_tag`.
14250b3e0c7STimur Tabi     start_tag: u16,
14350b3e0c7STimur Tabi }
14450b3e0c7STimur Tabi 
14550b3e0c7STimur Tabi impl FwsecFirmwareWithBl {
14650b3e0c7STimur Tabi     /// Loads the bootloader firmware for `dev` and `chipset`, and wrap `firmware` so it can be
14750b3e0c7STimur Tabi     /// loaded using it.
14850b3e0c7STimur Tabi     pub(crate) fn new(
14950b3e0c7STimur Tabi         firmware: FwsecFirmware,
15050b3e0c7STimur Tabi         dev: &Device<device::Bound>,
15150b3e0c7STimur Tabi         chipset: Chipset,
15250b3e0c7STimur Tabi     ) -> Result<Self> {
15350b3e0c7STimur Tabi         let fw = request_firmware(dev, chipset, "gen_bootloader", FIRMWARE_VERSION)?;
15450b3e0c7STimur Tabi         let hdr = fw
15550b3e0c7STimur Tabi             .data()
15650b3e0c7STimur Tabi             .get(0..size_of::<BinHdr>())
15750b3e0c7STimur Tabi             .and_then(BinHdr::from_bytes_copy)
15850b3e0c7STimur Tabi             .ok_or(EINVAL)?;
15950b3e0c7STimur Tabi 
16050b3e0c7STimur Tabi         let desc = {
16150b3e0c7STimur Tabi             let desc_offset = usize::from_safe_cast(hdr.header_offset);
16250b3e0c7STimur Tabi 
16350b3e0c7STimur Tabi             fw.data()
16450b3e0c7STimur Tabi                 .get(desc_offset..)
16550b3e0c7STimur Tabi                 .and_then(BootloaderDesc::from_bytes_copy_prefix)
16650b3e0c7STimur Tabi                 .ok_or(EINVAL)?
16750b3e0c7STimur Tabi                 .0
16850b3e0c7STimur Tabi         };
16950b3e0c7STimur Tabi 
17050b3e0c7STimur Tabi         let ucode = {
17150b3e0c7STimur Tabi             let ucode_start = usize::from_safe_cast(hdr.data_offset);
17250b3e0c7STimur Tabi             let code_size = usize::from_safe_cast(desc.code_size);
17350b3e0c7STimur Tabi             // Align to falcon block size (256 bytes).
17450b3e0c7STimur Tabi             let aligned_code_size = code_size
17550b3e0c7STimur Tabi                 .align_up(Alignment::new::<{ falcon::MEM_BLOCK_ALIGNMENT }>())
17650b3e0c7STimur Tabi                 .ok_or(EINVAL)?;
17750b3e0c7STimur Tabi 
17850b3e0c7STimur Tabi             let mut ucode = KVec::with_capacity(aligned_code_size, GFP_KERNEL)?;
17950b3e0c7STimur Tabi             ucode.extend_from_slice(
18050b3e0c7STimur Tabi                 fw.data()
18150b3e0c7STimur Tabi                     .get(ucode_start..ucode_start + code_size)
18250b3e0c7STimur Tabi                     .ok_or(EINVAL)?,
18350b3e0c7STimur Tabi                 GFP_KERNEL,
18450b3e0c7STimur Tabi             )?;
18550b3e0c7STimur Tabi             ucode.resize(aligned_code_size, 0, GFP_KERNEL)?;
18650b3e0c7STimur Tabi 
18750b3e0c7STimur Tabi             ucode
18850b3e0c7STimur Tabi         };
18950b3e0c7STimur Tabi 
19050b3e0c7STimur Tabi         // `BootloaderDmemDescV2` expects the source to be a mirror image of the destination and
19150b3e0c7STimur Tabi         // uses the same offset parameter for both.
19250b3e0c7STimur Tabi         //
19350b3e0c7STimur Tabi         // Thus, the start of the source object needs to be padded with the difference between the
19450b3e0c7STimur Tabi         // destination and source offsets.
19550b3e0c7STimur Tabi         //
19650b3e0c7STimur Tabi         // In practice, this is expected to always be zero but is required for code correctness.
19750b3e0c7STimur Tabi         let (align_padding, firmware_dma) = {
19850b3e0c7STimur Tabi             let align_padding = {
19950b3e0c7STimur Tabi                 let imem_sec = firmware.imem_sec_load_params();
20050b3e0c7STimur Tabi 
20150b3e0c7STimur Tabi                 imem_sec
20250b3e0c7STimur Tabi                     .dst_start
20350b3e0c7STimur Tabi                     .checked_sub(imem_sec.src_start)
20450b3e0c7STimur Tabi                     .map(usize::from_safe_cast)
20550b3e0c7STimur Tabi                     .ok_or(EOVERFLOW)?
20650b3e0c7STimur Tabi             };
20750b3e0c7STimur Tabi 
20850b3e0c7STimur Tabi             let mut firmware_obj = KVVec::new();
20950b3e0c7STimur Tabi             firmware_obj.extend_with(align_padding, 0u8, GFP_KERNEL)?;
21050b3e0c7STimur Tabi             firmware_obj.extend_from_slice(firmware.ucode.0.as_slice(), GFP_KERNEL)?;
21150b3e0c7STimur Tabi 
21250b3e0c7STimur Tabi             (
21350b3e0c7STimur Tabi                 align_padding,
214*1f9283afSAlexandre Courbot                 Coherent::from_slice(dev, firmware_obj.as_slice(), GFP_KERNEL)?,
21550b3e0c7STimur Tabi             )
21650b3e0c7STimur Tabi         };
21750b3e0c7STimur Tabi 
21850b3e0c7STimur Tabi         let dmem_desc = {
21950b3e0c7STimur Tabi             // Bootloader payload is in non-coherent system memory.
22050b3e0c7STimur Tabi             const FALCON_DMAIDX_PHYS_SYS_NCOH: u32 = 4;
22150b3e0c7STimur Tabi 
22250b3e0c7STimur Tabi             let imem_sec = firmware.imem_sec_load_params();
22350b3e0c7STimur Tabi             let imem_ns = firmware.imem_ns_load_params().ok_or(EINVAL)?;
22450b3e0c7STimur Tabi             let dmem = firmware.dmem_load_params();
22550b3e0c7STimur Tabi 
22650b3e0c7STimur Tabi             // The bootloader does not have a data destination offset field and copies the data at
22750b3e0c7STimur Tabi             // the start of DMEM, so it can only be used if the destination offset of the firmware
22850b3e0c7STimur Tabi             // is 0.
22950b3e0c7STimur Tabi             if dmem.dst_start != 0 {
23050b3e0c7STimur Tabi                 return Err(EINVAL);
23150b3e0c7STimur Tabi             }
23250b3e0c7STimur Tabi 
23350b3e0c7STimur Tabi             BootloaderDmemDescV2 {
23450b3e0c7STimur Tabi                 reserved: [0; 4],
23550b3e0c7STimur Tabi                 signature: [0; 4],
23650b3e0c7STimur Tabi                 ctx_dma: FALCON_DMAIDX_PHYS_SYS_NCOH,
23750b3e0c7STimur Tabi                 code_dma_base: firmware_dma.dma_handle(),
23850b3e0c7STimur Tabi                 // `dst_start` is also valid as the source offset since the firmware DMA object is
23950b3e0c7STimur Tabi                 // a mirror image of the target IMEM layout.
24050b3e0c7STimur Tabi                 non_sec_code_off: imem_ns.dst_start,
24150b3e0c7STimur Tabi                 non_sec_code_size: imem_ns.len,
24250b3e0c7STimur Tabi                 // `dst_start` is also valid as the source offset since the firmware DMA object is
24350b3e0c7STimur Tabi                 // a mirror image of the target IMEM layout.
24450b3e0c7STimur Tabi                 sec_code_off: imem_sec.dst_start,
24550b3e0c7STimur Tabi                 sec_code_size: imem_sec.len,
24650b3e0c7STimur Tabi                 code_entry_point: 0,
24750b3e0c7STimur Tabi                 // Start of data section is the added padding + the DMEM `src_start` field.
24850b3e0c7STimur Tabi                 data_dma_base: firmware_dma
24950b3e0c7STimur Tabi                     .dma_handle()
25050b3e0c7STimur Tabi                     .checked_add(u64::from_safe_cast(align_padding))
25150b3e0c7STimur Tabi                     .and_then(|offset| offset.checked_add(dmem.src_start.into()))
25250b3e0c7STimur Tabi                     .ok_or(EOVERFLOW)?,
25350b3e0c7STimur Tabi                 data_size: dmem.len,
25450b3e0c7STimur Tabi                 argc: 0,
25550b3e0c7STimur Tabi                 argv: 0,
25650b3e0c7STimur Tabi             }
25750b3e0c7STimur Tabi         };
25850b3e0c7STimur Tabi 
25950b3e0c7STimur Tabi         // The bootloader's code must be loaded in the area right below the first 64K of IMEM.
26050b3e0c7STimur Tabi         const BOOTLOADER_LOAD_CEILING: usize = sizes::SZ_64K;
26150b3e0c7STimur Tabi         let imem_dst_start = BOOTLOADER_LOAD_CEILING
26250b3e0c7STimur Tabi             .checked_sub(ucode.len())
26350b3e0c7STimur Tabi             .ok_or(EOVERFLOW)?;
26450b3e0c7STimur Tabi 
26550b3e0c7STimur Tabi         Ok(Self {
26650b3e0c7STimur Tabi             _firmware_dma: firmware_dma,
26750b3e0c7STimur Tabi             ucode,
26850b3e0c7STimur Tabi             dmem_desc,
26950b3e0c7STimur Tabi             brom_params: firmware.brom_params(),
27050b3e0c7STimur Tabi             imem_dst_start: u16::try_from(imem_dst_start)?,
27150b3e0c7STimur Tabi             start_tag: u16::try_from(desc.start_tag)?,
27250b3e0c7STimur Tabi         })
27350b3e0c7STimur Tabi     }
27450b3e0c7STimur Tabi 
27550b3e0c7STimur Tabi     /// Loads the bootloader into `falcon` and execute it.
27650b3e0c7STimur Tabi     ///
27750b3e0c7STimur Tabi     /// The bootloader will load the FWSEC firmware and then execute it. This function returns
27850b3e0c7STimur Tabi     /// after FWSEC has reached completion.
27950b3e0c7STimur Tabi     pub(crate) fn run(
28050b3e0c7STimur Tabi         &self,
28150b3e0c7STimur Tabi         dev: &Device<device::Bound>,
28250b3e0c7STimur Tabi         falcon: &Falcon<Gsp>,
28350b3e0c7STimur Tabi         bar: &Bar0,
28450b3e0c7STimur Tabi     ) -> Result<()> {
28550b3e0c7STimur Tabi         // Reset falcon, load the firmware, and run it.
28650b3e0c7STimur Tabi         falcon
28750b3e0c7STimur Tabi             .reset(bar)
28850b3e0c7STimur Tabi             .inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
28950b3e0c7STimur Tabi         falcon
29050b3e0c7STimur Tabi             .pio_load(bar, self)
29150b3e0c7STimur Tabi             .inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?;
29250b3e0c7STimur Tabi 
29350b3e0c7STimur Tabi         // Configure DMA index for the bootloader to fetch the FWSEC firmware from system memory.
29438f7e545SAlexandre Courbot         bar.update(
29538f7e545SAlexandre Courbot             regs::NV_PFALCON_FBIF_TRANSCFG::of::<Gsp>()
29638f7e545SAlexandre Courbot                 .try_at(usize::from_safe_cast(self.dmem_desc.ctx_dma))
29738f7e545SAlexandre Courbot                 .ok_or(EINVAL)?,
29850b3e0c7STimur Tabi             |v| {
29938f7e545SAlexandre Courbot                 v.with_target(FalconFbifTarget::CoherentSysmem)
30038f7e545SAlexandre Courbot                     .with_mem_type(FalconFbifMemType::Physical)
30150b3e0c7STimur Tabi             },
30238f7e545SAlexandre Courbot         );
30350b3e0c7STimur Tabi 
30450b3e0c7STimur Tabi         let (mbox0, _) = falcon
30550b3e0c7STimur Tabi             .boot(bar, Some(0), None)
30650b3e0c7STimur Tabi             .inspect_err(|e| dev_err!(dev, "Failed to boot FWSEC firmware: {:?}\n", e))?;
30750b3e0c7STimur Tabi         if mbox0 != 0 {
30850b3e0c7STimur Tabi             dev_err!(dev, "FWSEC firmware returned error {}\n", mbox0);
30950b3e0c7STimur Tabi             Err(EIO)
31050b3e0c7STimur Tabi         } else {
31150b3e0c7STimur Tabi             Ok(())
31250b3e0c7STimur Tabi         }
31350b3e0c7STimur Tabi     }
31450b3e0c7STimur Tabi }
31550b3e0c7STimur Tabi 
31650b3e0c7STimur Tabi impl FalconFirmware for FwsecFirmwareWithBl {
31750b3e0c7STimur Tabi     type Target = Gsp;
31850b3e0c7STimur Tabi 
31950b3e0c7STimur Tabi     fn brom_params(&self) -> FalconBromParams {
32050b3e0c7STimur Tabi         self.brom_params.clone()
32150b3e0c7STimur Tabi     }
32250b3e0c7STimur Tabi 
32350b3e0c7STimur Tabi     fn boot_addr(&self) -> u32 {
32450b3e0c7STimur Tabi         // On V2 platforms, the boot address is extracted from the generic bootloader, because the
32550b3e0c7STimur Tabi         // gbl is what actually copies FWSEC into memory, so that is what needs to be booted.
32650b3e0c7STimur Tabi         u32::from(self.start_tag) << 8
32750b3e0c7STimur Tabi     }
32850b3e0c7STimur Tabi }
32950b3e0c7STimur Tabi 
33050b3e0c7STimur Tabi impl FalconPioLoadable for FwsecFirmwareWithBl {
33150b3e0c7STimur Tabi     fn imem_sec_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> {
33250b3e0c7STimur Tabi         None
33350b3e0c7STimur Tabi     }
33450b3e0c7STimur Tabi 
33550b3e0c7STimur Tabi     fn imem_ns_load_params(&self) -> Option<FalconPioImemLoadTarget<'_>> {
33650b3e0c7STimur Tabi         Some(FalconPioImemLoadTarget {
33750b3e0c7STimur Tabi             data: self.ucode.as_ref(),
33850b3e0c7STimur Tabi             dst_start: self.imem_dst_start,
33950b3e0c7STimur Tabi             secure: false,
34050b3e0c7STimur Tabi             start_tag: self.start_tag,
34150b3e0c7STimur Tabi         })
34250b3e0c7STimur Tabi     }
34350b3e0c7STimur Tabi 
34450b3e0c7STimur Tabi     fn dmem_load_params(&self) -> FalconPioDmemLoadTarget<'_> {
34550b3e0c7STimur Tabi         FalconPioDmemLoadTarget {
34650b3e0c7STimur Tabi             data: self.dmem_desc.as_bytes(),
34750b3e0c7STimur Tabi             dst_start: 0,
34850b3e0c7STimur Tabi         }
34950b3e0c7STimur Tabi     }
35050b3e0c7STimur Tabi }
351