summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Courbot <acourbot@nvidia.com>2025-10-27 23:12:31 +0900
committerAlexandre Courbot <acourbot@nvidia.com>2025-11-08 08:22:45 +0900
commit84e2b401bcc551e7c2e1a995f90cce421bce5bfd (patch)
tree22c198ec547b70bb4dce9ade00601d5eb0a8eb84
parent5525ac03ca7adec61d39f3fd3a143b5e294bdff7 (diff)
gpu: nova-core: replace use of `as` with functions from `num`
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>
-rw-r--r--drivers/gpu/nova-core/falcon.rs8
-rw-r--r--drivers/gpu/nova-core/fb.rs7
-rw-r--r--drivers/gpu/nova-core/firmware.rs12
-rw-r--r--drivers/gpu/nova-core/firmware/booter.rs37
-rw-r--r--drivers/gpu/nova-core/firmware/fwsec.rs17
-rw-r--r--drivers/gpu/nova-core/firmware/gsp.rs6
-rw-r--r--drivers/gpu/nova-core/firmware/riscv.rs9
-rw-r--r--drivers/gpu/nova-core/num.rs2
-rw-r--r--drivers/gpu/nova-core/regs.rs5
-rw-r--r--drivers/gpu/nova-core/vbios.rs9
10 files changed, 70 insertions, 42 deletions
diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 8efc910f20af..0116cb918fc8 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -22,6 +22,10 @@ use crate::{
dma::DmaObject,
driver::Bar0,
gpu::Chipset,
+ num::{
+ FromSafeCast,
+ IntoSafeCast, //
+ },
regs,
regs::macros::RegisterBase, //
};
@@ -450,7 +454,7 @@ impl<E: FalconEngine + 'static> Falcon<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 @@ impl<E: FalconEngine + 'static> Falcon<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);
}
diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs
index 989bbfd5bdee..a99223f73367 100644
--- a/drivers/gpu/nova-core/fb.rs
+++ b/drivers/gpu/nova-core/fb.rs
@@ -17,6 +17,7 @@ use crate::{
dma::DmaObject,
driver::Bar0,
gpu::Chipset,
+ num::usize_as_u64,
regs, //
};
@@ -112,14 +113,14 @@ impl FbLayout {
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 @@ impl FbLayout {
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
diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs
index 163b746f03ef..2d2008b33fb4 100644
--- a/drivers/gpu/nova-core/firmware.rs
+++ b/drivers/gpu/nova-core/firmware.rs
@@ -16,7 +16,11 @@ use kernel::{
use crate::{
dma::DmaObject,
falcon::FalconFirmware,
- gpu, //
+ gpu,
+ num::{
+ FromSafeCast,
+ IntoSafeCast, //
+ },
};
pub(crate) mod booter;
@@ -78,7 +82,7 @@ impl FalconUCodeDescV3 {
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 @@ impl<'a> BinFirmware<'a> {
/// 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)
}
diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs
index 1e8f6c99fa2e..f107f753214a 100644
--- a/drivers/gpu/nova-core/firmware/booter.rs
+++ b/drivers/gpu/nova-core/firmware/booter.rs
@@ -34,6 +34,10 @@ use crate::{
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 @@ 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
@@ -108,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())
}
};
@@ -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 @@ 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)?,
)
@@ -335,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 cb794e406395..b28e34d279f4 100644
--- a/drivers/gpu/nova-core/firmware/fwsec.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec.rs
@@ -46,6 +46,10 @@ use crate::{
Signed,
Unsigned, //
},
+ num::{
+ FromSafeCast,
+ IntoSafeCast, //
+ },
vbios::Vbios,
};
@@ -267,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) }?;
@@ -292,7 +296,10 @@ impl FirmwareDmaObject<FwsecFirmware, Unsigned> {
// 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 @@ impl FirmwareDmaObject<FwsecFirmware, Unsigned> {
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 @@ 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)?;
@@ -384,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 939e036896bf..72766feae36e 100644
--- a/drivers/gpu/nova-core/firmware/gsp.rs
+++ b/drivers/gpu/nova-core/firmware/gsp.rs
@@ -24,6 +24,7 @@ use crate::{
Chipset, //
},
gsp::GSP_PAGE_SIZE,
+ num::FromSafeCast,
};
/// Ad-hoc and temporary module to extract sections from ELF images.
@@ -245,10 +246,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 196dedb96aeb..270b2c7dc219 100644
--- a/drivers/gpu/nova-core/firmware/riscv.rs
+++ b/drivers/gpu/nova-core/firmware/riscv.rs
@@ -14,7 +14,8 @@ use kernel::{
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 @@ 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)?)?
};
diff --git a/drivers/gpu/nova-core/num.rs b/drivers/gpu/nova-core/num.rs
index 457a1303640f..92a91b9e30de 100644
--- a/drivers/gpu/nova-core/num.rs
+++ b/drivers/gpu/nova-core/num.rs
@@ -106,7 +106,6 @@ impl_safe_as!(usize as { u32 });
///
/// 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 @@ impl FromSafeCast<u64> for usize {
///
/// 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;
diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs
index 7cd2e8a4d4c6..934003cab8a8 100644
--- a/drivers/gpu/nova-core/regs.rs
+++ b/drivers/gpu/nova-core/regs.rs
@@ -26,6 +26,7 @@ use crate::{
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 @@ register!(
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)
}
}
diff --git a/drivers/gpu/nova-core/vbios.rs b/drivers/gpu/nova-core/vbios.rs
index 9c5b93adeb96..abf423560ff4 100644
--- a/drivers/gpu/nova-core/vbios.rs
+++ b/drivers/gpu/nova-core/vbios.rs
@@ -21,6 +21,7 @@ use crate::{
fwsec::Bcrt30Rsa3kSignature,
FalconUCodeDescV3, //
},
+ num::FromSafeCast,
};
/// The offset of the VBIOS ROM in the BAR0 space.
@@ -795,7 +796,7 @@ impl PciAtBiosImage {
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 @@ impl FwSecBiosBuilder {
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 @@ impl FwSecBiosBuilder {
.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 @@ impl FwSecBiosImage {
// 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