diff options
Diffstat (limited to 'drivers/gpu/nova-core/firmware')
| -rw-r--r-- | drivers/gpu/nova-core/firmware/booter.rs | 82 | ||||
| -rw-r--r-- | drivers/gpu/nova-core/firmware/fwsec.rs | 188 | ||||
| -rw-r--r-- | drivers/gpu/nova-core/firmware/gsp.rs | 53 | ||||
| -rw-r--r-- | drivers/gpu/nova-core/firmware/riscv.rs | 34 |
4 files changed, 212 insertions, 145 deletions
diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs index b4ff1b17e4a0..f107f753214a 100644 --- a/drivers/gpu/nova-core/firmware/booter.rs +++ b/drivers/gpu/nova-core/firmware/booter.rs @@ -4,20 +4,41 @@ //! running on [`Sec2`], that is used on Turing/Ampere to load the GSP firmware into the GSP falcon //! (and optionally unload it through a separate firmware image). -use core::marker::PhantomData; -use core::mem::size_of; -use core::ops::Deref; - -use kernel::device; -use kernel::prelude::*; -use kernel::transmute::FromBytes; - -use crate::dma::DmaObject; -use crate::driver::Bar0; -use crate::falcon::sec2::Sec2; -use crate::falcon::{Falcon, FalconBromParams, FalconFirmware, FalconLoadParams, FalconLoadTarget}; -use crate::firmware::{BinFirmware, FirmwareDmaObject, FirmwareSignature, Signed, Unsigned}; -use crate::gpu::Chipset; +use core::{ + marker::PhantomData, + ops::Deref, // +}; + +use kernel::{ + device, + prelude::*, + transmute::FromBytes, // +}; + +use crate::{ + dma::DmaObject, + driver::Bar0, + falcon::{ + sec2::Sec2, + Falcon, + FalconBromParams, + FalconFirmware, + FalconLoadParams, + FalconLoadTarget, // + }, + firmware::{ + BinFirmware, + FirmwareDmaObject, + FirmwareSignature, + Signed, + Unsigned, // + }, + gpu::Chipset, + num::{ + FromSafeCast, + IntoSafeCast, // + }, +}; /// Local convenience function to return a copy of `S` by reinterpreting the bytes starting at /// `offset` in `slice`. @@ -74,7 +95,7 @@ impl<'a> HsFirmwareV2<'a> { /// /// Fails if the header pointed at by `bin_fw` is not within the bounds of the firmware image. fn new(bin_fw: &BinFirmware<'a>) -> Result<Self> { - frombytes_at::<HsHeaderV2>(bin_fw.fw, bin_fw.hdr.header_offset as usize) + frombytes_at::<HsHeaderV2>(bin_fw.fw, bin_fw.hdr.header_offset.into_safe_cast()) .map(|hdr| Self { hdr, fw: bin_fw.fw }) } @@ -83,7 +104,7 @@ impl<'a> HsFirmwareV2<'a> { /// Fails if the offset of the patch location is outside the bounds of the firmware /// image. fn patch_location(&self) -> Result<u32> { - frombytes_at::<u32>(self.fw, self.hdr.patch_loc_offset as usize) + frombytes_at::<u32>(self.fw, self.hdr.patch_loc_offset.into_safe_cast()) } /// Returns an iterator to the signatures of the firmware. The iterator can be empty if the @@ -91,19 +112,23 @@ impl<'a> HsFirmwareV2<'a> { /// /// Fails if the pointed signatures are outside the bounds of the firmware image. fn signatures_iter(&'a self) -> Result<impl Iterator<Item = BooterSignature<'a>>> { - let num_sig = frombytes_at::<u32>(self.fw, self.hdr.num_sig_offset as usize)?; + let num_sig = frombytes_at::<u32>(self.fw, self.hdr.num_sig_offset.into_safe_cast())?; let iter = match self.hdr.sig_prod_size.checked_div(num_sig) { // If there are no signatures, return an iterator that will yield zero elements. None => (&[] as &[u8]).chunks_exact(1), Some(sig_size) => { - let patch_sig = frombytes_at::<u32>(self.fw, self.hdr.patch_sig_offset as usize)?; - let signatures_start = (self.hdr.sig_prod_offset + patch_sig) as usize; + let patch_sig = + frombytes_at::<u32>(self.fw, self.hdr.patch_sig_offset.into_safe_cast())?; + let signatures_start = usize::from_safe_cast(self.hdr.sig_prod_offset + patch_sig); self.fw // Get signatures range. - .get(signatures_start..signatures_start + self.hdr.sig_prod_size as usize) + .get( + signatures_start + ..signatures_start + usize::from_safe_cast(self.hdr.sig_prod_size), + ) .ok_or(EINVAL)? - .chunks_exact(sig_size as usize) + .chunks_exact(sig_size.into_safe_cast()) } }; @@ -132,9 +157,9 @@ impl HsSignatureParams { /// Fails if the meta data parameter of `hs_fw` is outside the bounds of the firmware image, or /// if its size doesn't match that of [`HsSignatureParams`]. fn new(hs_fw: &HsFirmwareV2<'_>) -> Result<Self> { - let start = hs_fw.hdr.meta_data_offset as usize; + let start = usize::from_safe_cast(hs_fw.hdr.meta_data_offset); let end = start - .checked_add(hs_fw.hdr.meta_data_size as usize) + .checked_add(hs_fw.hdr.meta_data_size.into_safe_cast()) .ok_or(EINVAL)?; hs_fw @@ -169,7 +194,7 @@ impl HsLoadHeaderV2 { /// /// Fails if the header pointed at by `hs_fw` is not within the bounds of the firmware image. fn new(hs_fw: &HsFirmwareV2<'_>) -> Result<Self> { - frombytes_at::<Self>(hs_fw.fw, hs_fw.hdr.header_offset as usize) + frombytes_at::<Self>(hs_fw.fw, hs_fw.hdr.header_offset.into_safe_cast()) } } @@ -198,12 +223,13 @@ impl HsLoadHeaderV2App { } else { frombytes_at::<Self>( hs_fw.fw, - (hs_fw.hdr.header_offset as usize) + usize::from_safe_cast(hs_fw.hdr.header_offset) // Skip the load header... .checked_add(size_of::<HsLoadHeaderV2>()) // ... and jump to app header `idx`. .and_then(|offset| { - offset.checked_add((idx as usize).checked_mul(size_of::<Self>())?) + offset + .checked_add(usize::from_safe_cast(idx).checked_mul(size_of::<Self>())?) }) .ok_or(EINVAL)?, ) @@ -318,12 +344,12 @@ impl BooterFirmware { dev_err!(dev, "invalid fuse version for Booter firmware\n"); return Err(EINVAL); }; - signatures.nth(idx as usize) + signatures.nth(idx.into_safe_cast()) } } .ok_or(EINVAL)?; - ucode.patch_signature(&signature, patch_loc as usize)? + ucode.patch_signature(&signature, patch_loc.into_safe_cast())? } }; diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs index 8edbb5c0572c..b28e34d279f4 100644 --- a/drivers/gpu/nova-core/firmware/fwsec.rs +++ b/drivers/gpu/nova-core/firmware/fwsec.rs @@ -10,20 +10,48 @@ //! - The command to be run, as this firmware can perform several tasks ; //! - The ucode signature, so the GSP falcon can run FWSEC in HS mode. -use core::marker::PhantomData; -use core::mem::{align_of, size_of}; -use core::ops::Deref; - -use kernel::device::{self, Device}; -use kernel::prelude::*; -use kernel::transmute::FromBytes; - -use crate::dma::DmaObject; -use crate::driver::Bar0; -use crate::falcon::gsp::Gsp; -use crate::falcon::{Falcon, FalconBromParams, FalconFirmware, FalconLoadParams, FalconLoadTarget}; -use crate::firmware::{FalconUCodeDescV3, FirmwareDmaObject, FirmwareSignature, Signed, Unsigned}; -use crate::vbios::Vbios; +use core::{ + marker::PhantomData, + mem::size_of, + ops::Deref, // +}; + +use kernel::{ + device::{ + self, + Device, // + }, + prelude::*, + transmute::{ + AsBytes, + FromBytes, // + }, +}; + +use crate::{ + dma::DmaObject, + driver::Bar0, + falcon::{ + gsp::Gsp, + Falcon, + FalconBromParams, + FalconFirmware, + FalconLoadParams, + FalconLoadTarget, // + }, + firmware::{ + FalconUCodeDescV3, + FirmwareDmaObject, + FirmwareSignature, + Signed, + Unsigned, // + }, + num::{ + FromSafeCast, + IntoSafeCast, // + }, + vbios::Vbios, +}; const NVFW_FALCON_APPIF_ID_DMEMMAPPER: u32 = 0x4; @@ -35,7 +63,7 @@ struct FalconAppifHdrV1 { entry_size: u8, entry_count: u8, } -// SAFETY: any byte sequence is valid for this struct. +// SAFETY: Any byte sequence is valid for this struct. unsafe impl FromBytes for FalconAppifHdrV1 {} #[repr(C, packed)] @@ -44,7 +72,7 @@ struct FalconAppifV1 { id: u32, dmem_base: u32, } -// SAFETY: any byte sequence is valid for this struct. +// SAFETY: Any byte sequence is valid for this struct. unsafe impl FromBytes for FalconAppifV1 {} #[derive(Debug)] @@ -68,8 +96,10 @@ struct FalconAppifDmemmapperV3 { ucode_cmd_mask1: u32, multi_tgt_tbl: u32, } -// SAFETY: any byte sequence is valid for this struct. +// SAFETY: Any byte sequence is valid for this struct. unsafe impl FromBytes for FalconAppifDmemmapperV3 {} +// SAFETY: This struct doesn't contain uninitialized bytes and doesn't have interior mutability. +unsafe impl AsBytes for FalconAppifDmemmapperV3 {} #[derive(Debug)] #[repr(C, packed)] @@ -80,8 +110,10 @@ struct ReadVbios { size: u32, flags: u32, } -// SAFETY: any byte sequence is valid for this struct. +// SAFETY: Any byte sequence is valid for this struct. unsafe impl FromBytes for ReadVbios {} +// SAFETY: This struct doesn't contain uninitialized bytes and doesn't have interior mutability. +unsafe impl AsBytes for ReadVbios {} #[derive(Debug)] #[repr(C, packed)] @@ -92,8 +124,10 @@ struct FrtsRegion { size: u32, ftype: u32, } -// SAFETY: any byte sequence is valid for this struct. +// SAFETY: Any byte sequence is valid for this struct. unsafe impl FromBytes for FrtsRegion {} +// SAFETY: This struct doesn't contain uninitialized bytes and doesn't have interior mutability. +unsafe impl AsBytes for FrtsRegion {} const NVFW_FRTS_CMD_REGION_TYPE_FB: u32 = 2; @@ -102,8 +136,10 @@ struct FrtsCmd { read_vbios: ReadVbios, frts_region: FrtsRegion, } -// SAFETY: any byte sequence is valid for this struct. +// SAFETY: Any byte sequence is valid for this struct. unsafe impl FromBytes for FrtsCmd {} +// SAFETY: This struct doesn't contain uninitialized bytes and doesn't have interior mutability. +unsafe impl AsBytes for FrtsCmd {} const NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS: u32 = 0x15; const NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB: u32 = 0x19; @@ -147,26 +183,15 @@ impl FirmwareSignature<FwsecFirmware> for Bcrt30Rsa3kSignature {} /// /// # Safety /// -/// Callers must ensure that the region of memory returned is not written for as long as the -/// returned reference is alive. -/// -/// TODO[TRSM][COHA]: Remove this and `transmute_mut` once `CoherentAllocation::as_slice` is -/// available and we have a way to transmute objects implementing FromBytes, e.g.: -/// https://lore.kernel.org/lkml/20250330234039.29814-1-christiansantoslima21@gmail.com/ -unsafe fn transmute<'a, 'b, T: Sized + FromBytes>( - fw: &'a DmaObject, - offset: usize, -) -> Result<&'b T> { - if offset + size_of::<T>() > fw.size() { - return Err(EINVAL); - } - if (fw.start_ptr() as usize + offset) % align_of::<T>() != 0 { - return Err(EINVAL); - } - - // SAFETY: we have checked that the pointer is properly aligned that its pointed memory is - // large enough the contains an instance of `T`, which implements `FromBytes`. - Ok(unsafe { &*(fw.start_ptr().add(offset).cast::<T>()) }) +/// * Callers must ensure that the device does not read/write to/from memory while the returned +/// reference is live. +/// * Callers must ensure that this call does not race with a write to the same region while +/// the returned reference is live. +unsafe fn transmute<T: Sized + FromBytes>(fw: &DmaObject, offset: usize) -> Result<&T> { + // SAFETY: The safety requirements of the function guarantee the device won't read + // or write to memory while the reference is alive and that this call won't race + // with writes to the same memory region. + T::from_bytes(unsafe { fw.as_slice(offset, size_of::<T>())? }).ok_or(EINVAL) } /// Reinterpret the area starting from `offset` in `fw` as a mutable instance of `T` (which must @@ -174,22 +199,18 @@ unsafe fn transmute<'a, 'b, T: Sized + FromBytes>( /// /// # Safety /// -/// Callers must ensure that the region of memory returned is not read or written for as long as -/// the returned reference is alive. -unsafe fn transmute_mut<'a, 'b, T: Sized + FromBytes>( - fw: &'a mut DmaObject, +/// * Callers must ensure that the device does not read/write to/from memory while the returned +/// slice is live. +/// * Callers must ensure that this call does not race with a read or write to the same region +/// while the returned slice is live. +unsafe fn transmute_mut<T: Sized + FromBytes + AsBytes>( + fw: &mut DmaObject, offset: usize, -) -> Result<&'b mut T> { - if offset + size_of::<T>() > fw.size() { - return Err(EINVAL); - } - if (fw.start_ptr_mut() as usize + offset) % align_of::<T>() != 0 { - return Err(EINVAL); - } - - // SAFETY: we have checked that the pointer is properly aligned that its pointed memory is - // large enough the contains an instance of `T`, which implements `FromBytes`. - Ok(unsafe { &mut *(fw.start_ptr_mut().add(offset).cast::<T>()) }) +) -> Result<&mut T> { + // SAFETY: The safety requirements of the function guarantee the device won't read + // or write to memory while the reference is alive and that this call won't race + // with writes or reads to the same memory region. + T::from_bytes_mut(unsafe { fw.as_slice_mut(offset, size_of::<T>())? }).ok_or(EINVAL) } /// The FWSEC microcode, extracted from the BIOS and to be run on the GSP falcon. @@ -250,7 +271,7 @@ impl FirmwareDmaObject<FwsecFirmware, Unsigned> { let ucode = bios.fwsec_image().ucode(desc)?; let mut dma_object = DmaObject::from_data(dev, ucode)?; - let hdr_offset = (desc.imem_load_size + desc.interface_offset) as usize; + let hdr_offset = usize::from_safe_cast(desc.imem_load_size + desc.interface_offset); // SAFETY: we have exclusive access to `dma_object`. let hdr: &FalconAppifHdrV1 = unsafe { transmute(&dma_object, hdr_offset) }?; @@ -259,61 +280,62 @@ impl FirmwareDmaObject<FwsecFirmware, Unsigned> { } // Find the DMEM mapper section in the firmware. - for i in 0..hdr.entry_count as usize { - let app: &FalconAppifV1 = + for i in 0..usize::from(hdr.entry_count) { // SAFETY: we have exclusive access to `dma_object`. - unsafe { + let app: &FalconAppifV1 = unsafe { transmute( &dma_object, - hdr_offset + hdr.header_size as usize + i * hdr.entry_size as usize + hdr_offset + usize::from(hdr.header_size) + i * usize::from(hdr.entry_size), ) }?; if app.id != NVFW_FALCON_APPIF_ID_DMEMMAPPER { continue; } + let dmem_base = app.dmem_base; // SAFETY: we have exclusive access to `dma_object`. let dmem_mapper: &mut FalconAppifDmemmapperV3 = unsafe { transmute_mut( &mut dma_object, - (desc.imem_load_size + app.dmem_base) as usize, + (desc.imem_load_size + dmem_base).into_safe_cast(), ) }?; + dmem_mapper.init_cmd = match cmd { + FwsecCommand::Frts { .. } => NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS, + FwsecCommand::Sb => NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB, + }; + let cmd_in_buffer_offset = dmem_mapper.cmd_in_buffer_offset; + // SAFETY: we have exclusive access to `dma_object`. let frts_cmd: &mut FrtsCmd = unsafe { transmute_mut( &mut dma_object, - (desc.imem_load_size + dmem_mapper.cmd_in_buffer_offset) as usize, + (desc.imem_load_size + cmd_in_buffer_offset).into_safe_cast(), ) }?; frts_cmd.read_vbios = ReadVbios { ver: 1, - hdr: size_of::<ReadVbios>() as u32, + hdr: u32::try_from(size_of::<ReadVbios>())?, addr: 0, size: 0, flags: 2, }; - - dmem_mapper.init_cmd = match cmd { - FwsecCommand::Frts { - frts_addr, - frts_size, - } => { - frts_cmd.frts_region = FrtsRegion { - ver: 1, - hdr: size_of::<FrtsRegion>() as u32, - addr: (frts_addr >> 12) as u32, - size: (frts_size >> 12) as u32, - ftype: NVFW_FRTS_CMD_REGION_TYPE_FB, - }; - - NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS - } - FwsecCommand::Sb => NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB, - }; + if let FwsecCommand::Frts { + frts_addr, + frts_size, + } = cmd + { + frts_cmd.frts_region = FrtsRegion { + ver: 1, + hdr: u32::try_from(size_of::<FrtsRegion>())?, + addr: u32::try_from(frts_addr >> 12)?, + size: u32::try_from(frts_size >> 12)?, + ftype: NVFW_FRTS_CMD_REGION_TYPE_FB, + }; + } // Return early as we found and patched the DMEMMAPPER region. return Ok(Self(dma_object, PhantomData)); @@ -338,7 +360,7 @@ impl FwsecFirmware { // Patch signature if needed. let desc = bios.fwsec_image().header()?; let ucode_signed = if desc.signature_count != 0 { - let sig_base_img = (desc.imem_load_size + desc.pkc_data_offset) as usize; + let sig_base_img = usize::from_safe_cast(desc.imem_load_size + desc.pkc_data_offset); let desc_sig_versions = u32::from(desc.signature_versions); let reg_fuse_version = falcon.signature_reg_fuse_version(bar, desc.engine_id_mask, desc.ucode_id)?; @@ -369,7 +391,7 @@ impl FwsecFirmware { // Mask of the bits of `desc_sig_versions` to preserve. let reg_fuse_version_mask = reg_fuse_version_bit.wrapping_sub(1); - (desc_sig_versions & reg_fuse_version_mask).count_ones() as usize + usize::from_safe_cast((desc_sig_versions & reg_fuse_version_mask).count_ones()) }; dev_dbg!(dev, "patching signature with index {}\n", signature_idx); diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs index 9b70095434c6..0549805282ab 100644 --- a/drivers/gpu/nova-core/firmware/gsp.rs +++ b/drivers/gpu/nova-core/firmware/gsp.rs @@ -2,16 +2,30 @@ use core::mem::size_of_val; -use kernel::device; -use kernel::dma::{DataDirection, DmaAddress}; -use kernel::kvec; -use kernel::prelude::*; -use kernel::scatterlist::{Owned, SGTable}; +use kernel::{ + device, + dma::{ + DataDirection, + DmaAddress, // + }, + kvec, + prelude::*, + scatterlist::{ + Owned, + SGTable, // + }, +}; -use crate::dma::DmaObject; -use crate::firmware::riscv::RiscvFirmware; -use crate::gpu::{Architecture, Chipset}; -use crate::gsp::GSP_PAGE_SIZE; +use crate::{ + dma::DmaObject, + firmware::riscv::RiscvFirmware, + gpu::{ + Architecture, + Chipset, // + }, + gsp::GSP_PAGE_SIZE, + num::FromSafeCast, +}; /// Ad-hoc and temporary module to extract sections from ELF images. /// @@ -129,11 +143,11 @@ pub(crate) struct GspFirmware { /// Level 0 page table (single 4KB page) with one entry: DMA address of first level 1 page. level0: DmaObject, /// Size in bytes of the firmware contained in [`Self::fw`]. - size: usize, + pub(crate) size: usize, /// Device-mapped GSP signatures matching the GPU's [`Chipset`]. - signatures: DmaObject, + pub(crate) signatures: DmaObject, /// GSP bootloader, verifies the GSP firmware before loading and running it. - bootloader: RiscvFirmware, + pub(crate) bootloader: RiscvFirmware, } impl GspFirmware { @@ -150,6 +164,7 @@ impl GspFirmware { let sigs_section = match chipset.arch() { Architecture::Ampere => ".fwsignature_ga10x", + Architecture::Ada => ".fwsignature_ad10x", _ => return Err(ENOTSUPP), }; let signatures = elf::elf64_section(fw.data(), sigs_section) @@ -202,10 +217,10 @@ impl GspFirmware { let mut level0_data = kvec![0u8; GSP_PAGE_SIZE]?; // Fill level 1 page entry. - #[allow(clippy::useless_conversion)] - let level1_entry = u64::from(level1.iter().next().unwrap().dma_address()); - let dst = &mut level0_data[..size_of_val(&level1_entry)]; - dst.copy_from_slice(&level1_entry.to_le_bytes()); + let level1_entry = level1.iter().next().ok_or(EINVAL)?; + let level1_entry_addr = level1_entry.dma_address(); + let dst = &mut level0_data[..size_of_val(&level1_entry_addr)]; + dst.copy_from_slice(&level1_entry_addr.to_le_bytes()); // Turn the level0 page table into a [`DmaObject`]. DmaObject::from_data(dev, &level0_data)? @@ -216,7 +231,6 @@ impl GspFirmware { })) } - #[expect(unused)] /// Returns the DMA handle of the radix3 level 0 page table. pub(crate) fn radix3_dma_handle(&self) -> DmaAddress { self.level0.dma_handle() @@ -231,10 +245,11 @@ impl GspFirmware { fn map_into_lvl(sg_table: &SGTable<Owned<VVec<u8>>>, mut dst: VVec<u8>) -> Result<VVec<u8>> { for sg_entry in sg_table.iter() { // Number of pages we need to map. - let num_pages = (sg_entry.dma_len() as usize).div_ceil(GSP_PAGE_SIZE); + let num_pages = usize::from_safe_cast(sg_entry.dma_len()).div_ceil(GSP_PAGE_SIZE); for i in 0..num_pages { - let entry = sg_entry.dma_address() + (i as u64 * GSP_PAGE_SIZE as u64); + let entry = sg_entry.dma_address() + + (u64::from_safe_cast(i) * u64::from_safe_cast(GSP_PAGE_SIZE)); dst.extend_from_slice(&entry.to_le_bytes(), GFP_KERNEL)?; } } diff --git a/drivers/gpu/nova-core/firmware/riscv.rs b/drivers/gpu/nova-core/firmware/riscv.rs index afb08f5bc4ba..28dfef63657a 100644 --- a/drivers/gpu/nova-core/firmware/riscv.rs +++ b/drivers/gpu/nova-core/firmware/riscv.rs @@ -5,13 +5,18 @@ use core::mem::size_of; -use kernel::device; -use kernel::firmware::Firmware; -use kernel::prelude::*; -use kernel::transmute::FromBytes; +use kernel::{ + device, + firmware::Firmware, + prelude::*, + transmute::FromBytes, // +}; -use crate::dma::DmaObject; -use crate::firmware::BinFirmware; +use crate::{ + dma::DmaObject, + firmware::BinFirmware, + num::FromSafeCast, // +}; /// Descriptor for microcode running on a RISC-V core. #[repr(C)] @@ -41,7 +46,7 @@ impl RmRiscvUCodeDesc { /// /// Fails if the header pointed at by `bin_fw` is not within the bounds of the firmware image. fn new(bin_fw: &BinFirmware<'_>) -> Result<Self> { - let offset = bin_fw.hdr.header_offset as usize; + let offset = usize::from_safe_cast(bin_fw.hdr.header_offset); bin_fw .fw @@ -52,18 +57,17 @@ impl RmRiscvUCodeDesc { } /// A parsed firmware for a RISC-V core, ready to be loaded and run. -#[expect(unused)] pub(crate) struct RiscvFirmware { /// Offset at which the code starts in the firmware image. - code_offset: u32, + pub(crate) code_offset: u32, /// Offset at which the data starts in the firmware image. - data_offset: u32, + pub(crate) data_offset: u32, /// Offset at which the manifest starts in the firmware image. - manifest_offset: u32, + pub(crate) manifest_offset: u32, /// Application version. - app_version: u32, + pub(crate) app_version: u32, /// Device-mapped firmware image. - ucode: DmaObject, + pub(crate) ucode: DmaObject, } impl RiscvFirmware { @@ -74,8 +78,8 @@ impl RiscvFirmware { let riscv_desc = RmRiscvUCodeDesc::new(&bin_fw)?; let ucode = { - let start = bin_fw.hdr.data_offset as usize; - let len = bin_fw.hdr.data_size as usize; + let start = usize::from_safe_cast(bin_fw.hdr.data_offset); + let len = usize::from_safe_cast(bin_fw.hdr.data_size); DmaObject::from_data(dev, fw.data().get(start..start + len).ok_or(EINVAL)?)? }; |
