Commit 84e2b401 authored by Alexandre Courbot's avatar Alexandre Courbot
Browse files

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: default avatarDanilo Krummrich <dakr@kernel.org>
[acourbot@nvidia.com: fix merge conflicts after rebase.]
Signed-off-by: default avatarAlexandre Courbot <acourbot@nvidia.com>
Message-ID: <20251029-nova-as-v3-5-6a30c7333ad9@nvidia.com>
parent 5525ac03
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -22,6 +22,10 @@
    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);
            }
+4 −3
Original line number Diff line number Diff line
@@ -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
+8 −4
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@
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)
    }
+23 −14
Original line number Diff line number Diff line
@@ -34,6 +34,10 @@
        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())?
            }
        };

+12 −5
Original line number Diff line number Diff line
@@ -46,6 +46,10 @@
        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);
Loading