Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+70 -42
+6 -2
drivers/gpu/nova-core/falcon.rs
··· 22 22 dma::DmaObject, 23 23 driver::Bar0, 24 24 gpu::Chipset, 25 + num::{ 26 + FromSafeCast, 27 + IntoSafeCast, // 28 + }, 25 29 regs, 26 30 regs::macros::RegisterBase, // 27 31 }; ··· 454 450 FalconMem::Imem => (load_offsets.src_start, fw.dma_handle()), 455 451 FalconMem::Dmem => ( 456 452 0, 457 - fw.dma_handle_with_offset(load_offsets.src_start as usize)?, 453 + fw.dma_handle_with_offset(load_offsets.src_start.into_safe_cast())?, 458 454 ), 459 455 }; 460 456 if dma_start % DmaAddress::from(DMA_LEN) > 0 { ··· 480 476 dev_err!(self.dev, "DMA transfer length overflow"); 481 477 return Err(EOVERFLOW); 482 478 } 483 - Some(upper_bound) if upper_bound as usize > fw.size() => { 479 + Some(upper_bound) if usize::from_safe_cast(upper_bound) > fw.size() => { 484 480 dev_err!(self.dev, "DMA transfer goes beyond range of DMA object"); 485 481 return Err(EINVAL); 486 482 }
+4 -3
drivers/gpu/nova-core/fb.rs
··· 17 17 dma::DmaObject, 18 18 driver::Bar0, 19 19 gpu::Chipset, 20 + num::usize_as_u64, 20 21 regs, // 21 22 }; 22 23 ··· 113 112 114 113 let vga_workspace = { 115 114 let vga_base = { 116 - const NV_PRAMIN_SIZE: u64 = SZ_1M as u64; 115 + const NV_PRAMIN_SIZE: u64 = usize_as_u64(SZ_1M); 117 116 let base = fb.end - NV_PRAMIN_SIZE; 118 117 119 118 if hal.supports_display(bar) { 120 119 match regs::NV_PDISP_VGA_WORKSPACE_BASE::read(bar).vga_workspace_addr() { 121 120 Some(addr) => { 122 121 if addr < base { 123 - const VBIOS_WORKSPACE_SIZE: u64 = SZ_128K as u64; 122 + const VBIOS_WORKSPACE_SIZE: u64 = usize_as_u64(SZ_128K); 124 123 125 124 // Point workspace address to end of framebuffer. 126 125 fb.end - VBIOS_WORKSPACE_SIZE ··· 140 139 141 140 let frts = { 142 141 const FRTS_DOWN_ALIGN: Alignment = Alignment::new::<SZ_128K>(); 143 - const FRTS_SIZE: u64 = SZ_1M as u64; 142 + const FRTS_SIZE: u64 = usize_as_u64(SZ_1M); 144 143 let frts_base = vga_workspace.start.align_down(FRTS_DOWN_ALIGN) - FRTS_SIZE; 145 144 146 145 frts_base..frts_base + FRTS_SIZE
+8 -4
drivers/gpu/nova-core/firmware.rs
··· 16 16 use crate::{ 17 17 dma::DmaObject, 18 18 falcon::FalconFirmware, 19 - gpu, // 19 + gpu, 20 + num::{ 21 + FromSafeCast, 22 + IntoSafeCast, // 23 + }, 20 24 }; 21 25 22 26 pub(crate) mod booter; ··· 82 78 const HDR_SIZE_SHIFT: u32 = 16; 83 79 const HDR_SIZE_MASK: u32 = 0xffff0000; 84 80 85 - ((self.hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT) as usize 81 + ((self.hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT).into_safe_cast() 86 82 } 87 83 } 88 84 ··· 197 193 /// Returns the data payload of the firmware, or `None` if the data range is out of bounds of 198 194 /// the firmware image. 199 195 fn data(&self) -> Option<&[u8]> { 200 - let fw_start = self.hdr.data_offset as usize; 201 - let fw_size = self.hdr.data_size as usize; 196 + let fw_start = usize::from_safe_cast(self.hdr.data_offset); 197 + let fw_size = usize::from_safe_cast(self.hdr.data_size); 202 198 203 199 self.fw.get(fw_start..fw_start + fw_size) 204 200 }
+23 -14
drivers/gpu/nova-core/firmware/booter.rs
··· 34 34 Unsigned, // 35 35 }, 36 36 gpu::Chipset, 37 + num::{ 38 + FromSafeCast, 39 + IntoSafeCast, // 40 + }, 37 41 }; 38 42 39 43 /// Local convenience function to return a copy of `S` by reinterpreting the bytes starting at ··· 95 91 /// 96 92 /// Fails if the header pointed at by `bin_fw` is not within the bounds of the firmware image. 97 93 fn new(bin_fw: &BinFirmware<'a>) -> Result<Self> { 98 - frombytes_at::<HsHeaderV2>(bin_fw.fw, bin_fw.hdr.header_offset as usize) 94 + frombytes_at::<HsHeaderV2>(bin_fw.fw, bin_fw.hdr.header_offset.into_safe_cast()) 99 95 .map(|hdr| Self { hdr, fw: bin_fw.fw }) 100 96 } 101 97 ··· 104 100 /// Fails if the offset of the patch location is outside the bounds of the firmware 105 101 /// image. 106 102 fn patch_location(&self) -> Result<u32> { 107 - frombytes_at::<u32>(self.fw, self.hdr.patch_loc_offset as usize) 103 + frombytes_at::<u32>(self.fw, self.hdr.patch_loc_offset.into_safe_cast()) 108 104 } 109 105 110 106 /// Returns an iterator to the signatures of the firmware. The iterator can be empty if the ··· 112 108 /// 113 109 /// Fails if the pointed signatures are outside the bounds of the firmware image. 114 110 fn signatures_iter(&'a self) -> Result<impl Iterator<Item = BooterSignature<'a>>> { 115 - let num_sig = frombytes_at::<u32>(self.fw, self.hdr.num_sig_offset as usize)?; 111 + let num_sig = frombytes_at::<u32>(self.fw, self.hdr.num_sig_offset.into_safe_cast())?; 116 112 let iter = match self.hdr.sig_prod_size.checked_div(num_sig) { 117 113 // If there are no signatures, return an iterator that will yield zero elements. 118 114 None => (&[] as &[u8]).chunks_exact(1), 119 115 Some(sig_size) => { 120 - let patch_sig = frombytes_at::<u32>(self.fw, self.hdr.patch_sig_offset as usize)?; 121 - let signatures_start = (self.hdr.sig_prod_offset + patch_sig) as usize; 116 + let patch_sig = 117 + frombytes_at::<u32>(self.fw, self.hdr.patch_sig_offset.into_safe_cast())?; 118 + let signatures_start = usize::from_safe_cast(self.hdr.sig_prod_offset + patch_sig); 122 119 123 120 self.fw 124 121 // Get signatures range. 125 - .get(signatures_start..signatures_start + self.hdr.sig_prod_size as usize) 122 + .get( 123 + signatures_start 124 + ..signatures_start + usize::from_safe_cast(self.hdr.sig_prod_size), 125 + ) 126 126 .ok_or(EINVAL)? 127 - .chunks_exact(sig_size as usize) 127 + .chunks_exact(sig_size.into_safe_cast()) 128 128 } 129 129 }; 130 130 ··· 157 149 /// Fails if the meta data parameter of `hs_fw` is outside the bounds of the firmware image, or 158 150 /// if its size doesn't match that of [`HsSignatureParams`]. 159 151 fn new(hs_fw: &HsFirmwareV2<'_>) -> Result<Self> { 160 - let start = hs_fw.hdr.meta_data_offset as usize; 152 + let start = usize::from_safe_cast(hs_fw.hdr.meta_data_offset); 161 153 let end = start 162 - .checked_add(hs_fw.hdr.meta_data_size as usize) 154 + .checked_add(hs_fw.hdr.meta_data_size.into_safe_cast()) 163 155 .ok_or(EINVAL)?; 164 156 165 157 hs_fw ··· 194 186 /// 195 187 /// Fails if the header pointed at by `hs_fw` is not within the bounds of the firmware image. 196 188 fn new(hs_fw: &HsFirmwareV2<'_>) -> Result<Self> { 197 - frombytes_at::<Self>(hs_fw.fw, hs_fw.hdr.header_offset as usize) 189 + frombytes_at::<Self>(hs_fw.fw, hs_fw.hdr.header_offset.into_safe_cast()) 198 190 } 199 191 } 200 192 ··· 223 215 } else { 224 216 frombytes_at::<Self>( 225 217 hs_fw.fw, 226 - (hs_fw.hdr.header_offset as usize) 218 + usize::from_safe_cast(hs_fw.hdr.header_offset) 227 219 // Skip the load header... 228 220 .checked_add(size_of::<HsLoadHeaderV2>()) 229 221 // ... and jump to app header `idx`. 230 222 .and_then(|offset| { 231 - offset.checked_add((idx as usize).checked_mul(size_of::<Self>())?) 223 + offset 224 + .checked_add(usize::from_safe_cast(idx).checked_mul(size_of::<Self>())?) 232 225 }) 233 226 .ok_or(EINVAL)?, 234 227 ) ··· 344 335 dev_err!(dev, "invalid fuse version for Booter firmware\n"); 345 336 return Err(EINVAL); 346 337 }; 347 - signatures.nth(idx as usize) 338 + signatures.nth(idx.into_safe_cast()) 348 339 } 349 340 } 350 341 .ok_or(EINVAL)?; 351 342 352 - ucode.patch_signature(&signature, patch_loc as usize)? 343 + ucode.patch_signature(&signature, patch_loc.into_safe_cast())? 353 344 } 354 345 }; 355 346
+12 -5
drivers/gpu/nova-core/firmware/fwsec.rs
··· 46 46 Signed, 47 47 Unsigned, // 48 48 }, 49 + num::{ 50 + FromSafeCast, 51 + IntoSafeCast, // 52 + }, 49 53 vbios::Vbios, 50 54 }; 51 55 ··· 271 267 let ucode = bios.fwsec_image().ucode(desc)?; 272 268 let mut dma_object = DmaObject::from_data(dev, ucode)?; 273 269 274 - let hdr_offset = (desc.imem_load_size + desc.interface_offset) as usize; 270 + let hdr_offset = usize::from_safe_cast(desc.imem_load_size + desc.interface_offset); 275 271 // SAFETY: we have exclusive access to `dma_object`. 276 272 let hdr: &FalconAppifHdrV1 = unsafe { transmute(&dma_object, hdr_offset) }?; 277 273 ··· 296 292 297 293 // SAFETY: we have exclusive access to `dma_object`. 298 294 let dmem_mapper: &mut FalconAppifDmemmapperV3 = unsafe { 299 - transmute_mut(&mut dma_object, (desc.imem_load_size + dmem_base) as usize) 295 + transmute_mut( 296 + &mut dma_object, 297 + (desc.imem_load_size + dmem_base).into_safe_cast(), 298 + ) 300 299 }?; 301 300 302 301 dmem_mapper.init_cmd = match cmd { ··· 312 305 let frts_cmd: &mut FrtsCmd = unsafe { 313 306 transmute_mut( 314 307 &mut dma_object, 315 - (desc.imem_load_size + cmd_in_buffer_offset) as usize, 308 + (desc.imem_load_size + cmd_in_buffer_offset).into_safe_cast(), 316 309 ) 317 310 }?; 318 311 ··· 360 353 // Patch signature if needed. 361 354 let desc = bios.fwsec_image().header()?; 362 355 let ucode_signed = if desc.signature_count != 0 { 363 - let sig_base_img = (desc.imem_load_size + desc.pkc_data_offset) as usize; 356 + let sig_base_img = usize::from_safe_cast(desc.imem_load_size + desc.pkc_data_offset); 364 357 let desc_sig_versions = u32::from(desc.signature_versions); 365 358 let reg_fuse_version = 366 359 falcon.signature_reg_fuse_version(bar, desc.engine_id_mask, desc.ucode_id)?; ··· 391 384 // Mask of the bits of `desc_sig_versions` to preserve. 392 385 let reg_fuse_version_mask = reg_fuse_version_bit.wrapping_sub(1); 393 386 394 - (desc_sig_versions & reg_fuse_version_mask).count_ones() as usize 387 + usize::from_safe_cast((desc_sig_versions & reg_fuse_version_mask).count_ones()) 395 388 }; 396 389 397 390 dev_dbg!(dev, "patching signature with index {}\n", signature_idx);
+4 -2
drivers/gpu/nova-core/firmware/gsp.rs
··· 24 24 Chipset, // 25 25 }, 26 26 gsp::GSP_PAGE_SIZE, 27 + num::FromSafeCast, 27 28 }; 28 29 29 30 /// Ad-hoc and temporary module to extract sections from ELF images. ··· 246 245 fn map_into_lvl(sg_table: &SGTable<Owned<VVec<u8>>>, mut dst: VVec<u8>) -> Result<VVec<u8>> { 247 246 for sg_entry in sg_table.iter() { 248 247 // Number of pages we need to map. 249 - let num_pages = (sg_entry.dma_len() as usize).div_ceil(GSP_PAGE_SIZE); 248 + let num_pages = usize::from_safe_cast(sg_entry.dma_len()).div_ceil(GSP_PAGE_SIZE); 250 249 251 250 for i in 0..num_pages { 252 - let entry = sg_entry.dma_address() + (i as u64 * GSP_PAGE_SIZE as u64); 251 + let entry = sg_entry.dma_address() 252 + + (u64::from_safe_cast(i) * u64::from_safe_cast(GSP_PAGE_SIZE)); 253 253 dst.extend_from_slice(&entry.to_le_bytes(), GFP_KERNEL)?; 254 254 } 255 255 }
+5 -4
drivers/gpu/nova-core/firmware/riscv.rs
··· 14 14 15 15 use crate::{ 16 16 dma::DmaObject, 17 - firmware::BinFirmware, // 17 + firmware::BinFirmware, 18 + num::FromSafeCast, // 18 19 }; 19 20 20 21 /// Descriptor for microcode running on a RISC-V core. ··· 46 45 /// 47 46 /// Fails if the header pointed at by `bin_fw` is not within the bounds of the firmware image. 48 47 fn new(bin_fw: &BinFirmware<'_>) -> Result<Self> { 49 - let offset = bin_fw.hdr.header_offset as usize; 48 + let offset = usize::from_safe_cast(bin_fw.hdr.header_offset); 50 49 51 50 bin_fw 52 51 .fw ··· 79 78 let riscv_desc = RmRiscvUCodeDesc::new(&bin_fw)?; 80 79 81 80 let ucode = { 82 - let start = bin_fw.hdr.data_offset as usize; 83 - let len = bin_fw.hdr.data_size as usize; 81 + let start = usize::from_safe_cast(bin_fw.hdr.data_offset); 82 + let len = usize::from_safe_cast(bin_fw.hdr.data_size); 84 83 85 84 DmaObject::from_data(dev, fw.data().get(start..start + len).ok_or(EINVAL)?)? 86 85 };
-2
drivers/gpu/nova-core/num.rs
··· 106 106 /// 107 107 /// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00u32 as usize); 108 108 /// ``` 109 - #[expect(unused)] 110 109 pub(crate) trait FromSafeCast<T> { 111 110 /// Create a `Self` from `value`. This operation is guaranteed to be lossless. 112 111 fn from_safe_cast(value: T) -> Self; ··· 149 150 /// 150 151 /// assert_eq!(0xf00u32.into_safe_cast(), 0xf00u32 as usize); 151 152 /// ``` 152 - #[expect(unused)] 153 153 pub(crate) trait IntoSafeCast<T> { 154 154 /// Convert `self` into a `T`. This operation is guaranteed to be lossless. 155 155 fn into_safe_cast(self) -> T;
+3 -2
drivers/gpu/nova-core/regs.rs
··· 26 26 Architecture, 27 27 Chipset, // 28 28 }, 29 + num::FromSafeCast, 29 30 }; 30 31 31 32 // PMC ··· 90 89 /// Returns the usable framebuffer size, in bytes. 91 90 pub(crate) fn usable_fb_size(self) -> u64 { 92 91 let size = (u64::from(self.lower_mag()) << u64::from(self.lower_scale())) 93 - * kernel::sizes::SZ_1M as u64; 92 + * u64::from_safe_cast(kernel::sizes::SZ_1M); 94 93 95 94 if self.ecc_mode_enabled() { 96 95 // Remove the amount of memory reserved for ECC (one per 16 units). ··· 173 172 impl NV_USABLE_FB_SIZE_IN_MB { 174 173 /// Returns the usable framebuffer size, in bytes. 175 174 pub(crate) fn usable_fb_size(self) -> u64 { 176 - u64::from(self.value()) * kernel::sizes::SZ_1M as u64 175 + u64::from(self.value()) * u64::from_safe_cast(kernel::sizes::SZ_1M) 177 176 } 178 177 } 179 178
+5 -4
drivers/gpu/nova-core/vbios.rs
··· 21 21 fwsec::Bcrt30Rsa3kSignature, 22 22 FalconUCodeDescV3, // 23 23 }, 24 + num::FromSafeCast, 24 25 }; 25 26 26 27 /// The offset of the VBIOS ROM in the BAR0 space. ··· 796 795 797 796 let data_ptr = u32::from_le_bytes(bytes); 798 797 799 - if (data_ptr as usize) < self.base.data.len() { 798 + if (usize::from_safe_cast(data_ptr)) < self.base.data.len() { 800 799 dev_err!(self.base.dev, "Falcon data pointer out of bounds\n"); 801 800 return Err(EINVAL); 802 801 } ··· 923 922 pci_at_image: &PciAtBiosImage, 924 923 first_fwsec: &FwSecBiosBuilder, 925 924 ) -> Result { 926 - let mut offset = pci_at_image.falcon_data_ptr()? as usize; 925 + let mut offset = usize::from_safe_cast(pci_at_image.falcon_data_ptr()?); 927 926 let mut pmu_in_first_fwsec = false; 928 927 929 928 // The falcon data pointer assumes that the PciAt and FWSEC images ··· 964 963 .find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD) 965 964 { 966 965 Ok(entry) => { 967 - let mut ucode_offset = entry.data as usize; 966 + let mut ucode_offset = usize::from_safe_cast(entry.data); 968 967 ucode_offset -= pci_at_image.base.data.len(); 969 968 if ucode_offset < first_fwsec.base.data.len() { 970 969 dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n"); ··· 1050 1049 1051 1050 // The ucode data follows the descriptor. 1052 1051 let ucode_data_offset = falcon_ucode_offset + desc.size(); 1053 - let size = (desc.imem_load_size + desc.dmem_load_size) as usize; 1052 + let size = usize::from_safe_cast(desc.imem_load_size + desc.dmem_load_size); 1054 1053 1055 1054 // Get the data slice, checking bounds in a single operation. 1056 1055 self.base