]> Gentwo Git Trees - linux/.git/commitdiff
gpu: nova-core: replace use of `as` with functions from `num`
authorAlexandre Courbot <acourbot@nvidia.com>
Mon, 27 Oct 2025 14:12:31 +0000 (23:12 +0900)
committerAlexandre Courbot <acourbot@nvidia.com>
Fri, 7 Nov 2025 23:22:45 +0000 (08:22 +0900)
Use the newly-introduced `num` module to replace the use of `as`
wherever it is safe to do. This ensures that a given conversion cannot
lose data if its source or destination type ever changes.

Acked-by: Danilo Krummrich <dakr@kernel.org>
[acourbot@nvidia.com: fix merge conflicts after rebase.]
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Message-ID: <20251029-nova-as-v3-5-6a30c7333ad9@nvidia.com>

drivers/gpu/nova-core/falcon.rs
drivers/gpu/nova-core/fb.rs
drivers/gpu/nova-core/firmware.rs
drivers/gpu/nova-core/firmware/booter.rs
drivers/gpu/nova-core/firmware/fwsec.rs
drivers/gpu/nova-core/firmware/gsp.rs
drivers/gpu/nova-core/firmware/riscv.rs
drivers/gpu/nova-core/num.rs
drivers/gpu/nova-core/regs.rs
drivers/gpu/nova-core/vbios.rs

index 8efc910f20afb920ce66dc44850b25cf062769fb..0116cb918fc846b8105dcdc81c6f52be7003ef7b 100644 (file)
     dma::DmaObject,
     driver::Bar0,
     gpu::Chipset,
+    num::{
+        FromSafeCast,
+        IntoSafeCast, //
+    },
     regs,
     regs::macros::RegisterBase, //
 };
@@ -450,7 +454,7 @@ fn dma_wr<F: FalconFirmware<Target = E>>(
             FalconMem::Imem => (load_offsets.src_start, fw.dma_handle()),
             FalconMem::Dmem => (
                 0,
-                fw.dma_handle_with_offset(load_offsets.src_start as usize)?,
+                fw.dma_handle_with_offset(load_offsets.src_start.into_safe_cast())?,
             ),
         };
         if dma_start % DmaAddress::from(DMA_LEN) > 0 {
@@ -476,7 +480,7 @@ fn dma_wr<F: FalconFirmware<Target = E>>(
                 dev_err!(self.dev, "DMA transfer length overflow");
                 return Err(EOVERFLOW);
             }
-            Some(upper_bound) if upper_bound as usize > fw.size() => {
+            Some(upper_bound) if usize::from_safe_cast(upper_bound) > fw.size() => {
                 dev_err!(self.dev, "DMA transfer goes beyond range of DMA object");
                 return Err(EINVAL);
             }
index 989bbfd5bdeefe28c4650f8c316c47f6d2a6c7aa..a99223f7336709a21e3e78b1c68855aedaa9a1e2 100644 (file)
@@ -17,6 +17,7 @@
     dma::DmaObject,
     driver::Bar0,
     gpu::Chipset,
+    num::usize_as_u64,
     regs, //
 };
 
@@ -112,14 +113,14 @@ pub(crate) fn new(chipset: Chipset, bar: &Bar0) -> Result<Self> {
 
         let vga_workspace = {
             let vga_base = {
-                const NV_PRAMIN_SIZE: u64 = SZ_1M as u64;
+                const NV_PRAMIN_SIZE: u64 = usize_as_u64(SZ_1M);
                 let base = fb.end - NV_PRAMIN_SIZE;
 
                 if hal.supports_display(bar) {
                     match regs::NV_PDISP_VGA_WORKSPACE_BASE::read(bar).vga_workspace_addr() {
                         Some(addr) => {
                             if addr < base {
-                                const VBIOS_WORKSPACE_SIZE: u64 = SZ_128K as u64;
+                                const VBIOS_WORKSPACE_SIZE: u64 = usize_as_u64(SZ_128K);
 
                                 // Point workspace address to end of framebuffer.
                                 fb.end - VBIOS_WORKSPACE_SIZE
@@ -139,7 +140,7 @@ pub(crate) fn new(chipset: Chipset, bar: &Bar0) -> Result<Self> {
 
         let frts = {
             const FRTS_DOWN_ALIGN: Alignment = Alignment::new::<SZ_128K>();
-            const FRTS_SIZE: u64 = SZ_1M as u64;
+            const FRTS_SIZE: u64 = usize_as_u64(SZ_1M);
             let frts_base = vga_workspace.start.align_down(FRTS_DOWN_ALIGN) - FRTS_SIZE;
 
             frts_base..frts_base + FRTS_SIZE
index 163b746f03ef3cf778bac0b4d662278f75a7e2eb..2d2008b33fb41383c4539ba6e13bad21eb26127f 100644 (file)
 use crate::{
     dma::DmaObject,
     falcon::FalconFirmware,
-    gpu, //
+    gpu,
+    num::{
+        FromSafeCast,
+        IntoSafeCast, //
+    },
 };
 
 pub(crate) mod booter;
@@ -78,7 +82,7 @@ pub(crate) fn size(&self) -> usize {
         const HDR_SIZE_SHIFT: u32 = 16;
         const HDR_SIZE_MASK: u32 = 0xffff0000;
 
-        ((self.hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT) as usize
+        ((self.hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT).into_safe_cast()
     }
 }
 
@@ -193,8 +197,8 @@ fn new(fw: &'a firmware::Firmware) -> Result<Self> {
     /// Returns the data payload of the firmware, or `None` if the data range is out of bounds of
     /// the firmware image.
     fn data(&self) -> Option<&[u8]> {
-        let fw_start = self.hdr.data_offset as usize;
-        let fw_size = self.hdr.data_size as usize;
+        let fw_start = usize::from_safe_cast(self.hdr.data_offset);
+        let fw_size = usize::from_safe_cast(self.hdr.data_size);
 
         self.fw.get(fw_start..fw_start + fw_size)
     }
index 1e8f6c99fa2e12f1805293225a7977a5b73a34a1..f107f753214a13fcc5959f27d1531a258e92742e 100644 (file)
         Unsigned, //
     },
     gpu::Chipset,
+    num::{
+        FromSafeCast,
+        IntoSafeCast, //
+    },
 };
 
 /// Local convenience function to return a copy of `S` by reinterpreting the bytes starting at
@@ -91,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 })
     }
 
@@ -100,7 +104,7 @@ fn new(bin_fw: &BinFirmware<'a>) -> Result<Self> {
     /// 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
@@ -108,19 +112,23 @@ fn patch_location(&self) -> Result<u32> {
     ///
     /// 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())
             }
         };
 
@@ -149,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
@@ -186,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())
     }
 }
 
@@ -215,12 +223,13 @@ fn new(hs_fw: &HsFirmwareV2<'_>, idx: u32) -> Result<Self> {
         } 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)?,
             )
@@ -335,12 +344,12 @@ pub(crate) fn new(
                             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())?
             }
         };
 
index cb794e4063957b2c0e8a5b7cebedf157cb701945..b28e34d279f4699b11191b180524a1552fe9eddd 100644 (file)
         Signed,
         Unsigned, //
     },
+    num::{
+        FromSafeCast,
+        IntoSafeCast, //
+    },
     vbios::Vbios,
 };
 
@@ -267,7 +271,7 @@ fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Re
         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) }?;
 
@@ -292,7 +296,10 @@ fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Re
 
             // SAFETY: we have exclusive access to `dma_object`.
             let dmem_mapper: &mut FalconAppifDmemmapperV3 = unsafe {
-                transmute_mut(&mut dma_object, (desc.imem_load_size + dmem_base) as usize)
+                transmute_mut(
+                    &mut dma_object,
+                    (desc.imem_load_size + dmem_base).into_safe_cast(),
+                )
             }?;
 
             dmem_mapper.init_cmd = match cmd {
@@ -305,7 +312,7 @@ fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Re
             let frts_cmd: &mut FrtsCmd = unsafe {
                 transmute_mut(
                     &mut dma_object,
-                    (desc.imem_load_size + cmd_in_buffer_offset) as usize,
+                    (desc.imem_load_size + cmd_in_buffer_offset).into_safe_cast(),
                 )
             }?;
 
@@ -353,7 +360,7 @@ pub(crate) fn new(
         // 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)?;
@@ -384,7 +391,7 @@ pub(crate) fn new(
                 // 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);
index 939e036896bfe67b5ec41880dbba80ad938b8b4f..72766feae36e0d9021997d3bf03663800e2fa122 100644 (file)
@@ -24,6 +24,7 @@
         Chipset, //
     },
     gsp::GSP_PAGE_SIZE,
+    num::FromSafeCast,
 };
 
 /// Ad-hoc and temporary module to extract sections from ELF images.
@@ -245,10 +246,11 @@ pub(crate) fn radix3_dma_handle(&self) -> DmaAddress {
 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)?;
         }
     }
index 196dedb96aeb7d4571809fff5dc08613aba5f063..270b2c7dc219663737717962568df5f1fc674231 100644 (file)
@@ -14,7 +14,8 @@
 
 use crate::{
     dma::DmaObject,
-    firmware::BinFirmware, //
+    firmware::BinFirmware,
+    num::FromSafeCast, //
 };
 
 /// Descriptor for microcode running on a RISC-V core.
@@ -45,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
@@ -78,8 +79,8 @@ pub(crate) fn new(dev: &device::Device<device::Bound>, fw: &Firmware) -> Result<
         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)?)?
         };
index 457a1303640f1917f182834c3d4f661c816cea38..92a91b9e30dea1c24d465f3cf107caced1a5b826 100644 (file)
@@ -106,7 +106,6 @@ pub(crate) const fn [<$from _as_ $into>](value: $from) -> $into {
 ///
 /// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00u32 as usize);
 /// ```
-#[expect(unused)]
 pub(crate) trait FromSafeCast<T> {
     /// Create a `Self` from `value`. This operation is guaranteed to be lossless.
     fn from_safe_cast(value: T) -> Self;
@@ -150,7 +149,6 @@ fn from_safe_cast(value: u64) -> Self {
 ///
 /// assert_eq!(0xf00u32.into_safe_cast(), 0xf00u32 as usize);
 /// ```
-#[expect(unused)]
 pub(crate) trait IntoSafeCast<T> {
     /// Convert `self` into a `T`. This operation is guaranteed to be lossless.
     fn into_safe_cast(self) -> T;
index 7cd2e8a4d4c6fe069fba7c168f692473c5cca930..934003cab8a82a0f88d3033d0e580459b9268c0a 100644 (file)
@@ -26,6 +26,7 @@
         Architecture,
         Chipset, //
     },
+    num::FromSafeCast,
 };
 
 // PMC
@@ -89,7 +90,7 @@ impl NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE {
     /// Returns the usable framebuffer size, in bytes.
     pub(crate) fn usable_fb_size(self) -> u64 {
         let size = (u64::from(self.lower_mag()) << u64::from(self.lower_scale()))
-            * kernel::sizes::SZ_1M as u64;
+            * u64::from_safe_cast(kernel::sizes::SZ_1M);
 
         if self.ecc_mode_enabled() {
             // Remove the amount of memory reserved for ECC (one per 16 units).
@@ -172,7 +173,7 @@ pub(crate) fn completed(self) -> bool {
 impl NV_USABLE_FB_SIZE_IN_MB {
     /// Returns the usable framebuffer size, in bytes.
     pub(crate) fn usable_fb_size(self) -> u64 {
-        u64::from(self.value()) * kernel::sizes::SZ_1M as u64
+        u64::from(self.value()) * u64::from_safe_cast(kernel::sizes::SZ_1M)
     }
 }
 
index 9c5b93adeb96b82c631f1539442a1616a5abe6bf..abf423560ff4efcfb15b3b26d6cf0dc3fbc0077c 100644 (file)
@@ -21,6 +21,7 @@
         fwsec::Bcrt30Rsa3kSignature,
         FalconUCodeDescV3, //
     },
+    num::FromSafeCast,
 };
 
 /// The offset of the VBIOS ROM in the BAR0 space.
@@ -795,7 +796,7 @@ fn falcon_data_ptr(&self) -> Result<u32> {
 
         let data_ptr = u32::from_le_bytes(bytes);
 
-        if (data_ptr as usize) < self.base.data.len() {
+        if (usize::from_safe_cast(data_ptr)) < self.base.data.len() {
             dev_err!(self.base.dev, "Falcon data pointer out of bounds\n");
             return Err(EINVAL);
         }
@@ -922,7 +923,7 @@ fn setup_falcon_data(
         pci_at_image: &PciAtBiosImage,
         first_fwsec: &FwSecBiosBuilder,
     ) -> Result {
-        let mut offset = pci_at_image.falcon_data_ptr()? as usize;
+        let mut offset = usize::from_safe_cast(pci_at_image.falcon_data_ptr()?);
         let mut pmu_in_first_fwsec = false;
 
         // The falcon data pointer assumes that the PciAt and FWSEC images
@@ -963,7 +964,7 @@ fn setup_falcon_data(
             .find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)
         {
             Ok(entry) => {
-                let mut ucode_offset = entry.data as usize;
+                let mut ucode_offset = usize::from_safe_cast(entry.data);
                 ucode_offset -= pci_at_image.base.data.len();
                 if ucode_offset < first_fwsec.base.data.len() {
                     dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n");
@@ -1049,7 +1050,7 @@ pub(crate) fn ucode(&self, desc: &FalconUCodeDescV3) -> Result<&[u8]> {
 
         // The ucode data follows the descriptor.
         let ucode_data_offset = falcon_ucode_offset + desc.size();
-        let size = (desc.imem_load_size + desc.dmem_load_size) as usize;
+        let size = usize::from_safe_cast(desc.imem_load_size + desc.dmem_load_size);
 
         // Get the data slice, checking bounds in a single operation.
         self.base