Commit 473f7785 authored by Daniel del Castillo's avatar Daniel del Castillo Committed by Alexandre Courbot
Browse files

gpu: nova-core: Simplify `transmute` and `transmute_mut` in fwsec.rs



This patch solves one of the existing mentions of COHA, a task
in the Nova task list about improving the `CoherentAllocation` API.
It uses the new `from_bytes` method from the `FromBytes` trait as
well as the `as_slice` and `as_slice_mut` methods from
`CoherentAllocation`.

Signed-off-by: default avatarDaniel del Castillo <delcastillodelarosadaniel@gmail.com>
[acourbot@nvidia.com: set prefix to "gpu: nova-core:".]
[acourbot@nvidia.com: fix merge conflict after imports refactor.]
Signed-off-by: default avatarAlexandre Courbot <acourbot@nvidia.com>
Message-ID: <20251104193756.57726-1-delcastillodelarosadaniel@gmail.com>
parent 173c99b8
Loading
Loading
Loading
Loading
+58 −67
Original line number Diff line number Diff line
@@ -12,11 +12,8 @@

use core::{
    marker::PhantomData,
    mem::{
        align_of,
        size_of, //
    },
    ops::Deref,
    mem::size_of,
    ops::Deref, //
};

use kernel::{
@@ -25,7 +22,10 @@
        Device, //
    },
    prelude::*,
    transmute::FromBytes,
    transmute::{
        AsBytes,
        FromBytes, //
    },
};

use crate::{
@@ -94,6 +94,8 @@ struct FalconAppifDmemmapperV3 {
}
// 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)]
@@ -106,6 +108,8 @@ struct ReadVbios {
}
// 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)]
@@ -118,6 +122,8 @@ struct FrtsRegion {
}
// 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;

@@ -128,6 +134,8 @@ struct FrtsCmd {
}
// 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;
@@ -171,26 +179,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
@@ -198,22 +195,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.
@@ -284,32 +277,35 @@ fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Re

        // Find the DMEM mapper section in the firmware.
        for i in 0..usize::from(hdr.entry_count) {
            let app: &FalconAppifV1 =
            // SAFETY: we have exclusive access to `dma_object`.
            unsafe {
            let app: &FalconAppifV1 = unsafe {
                transmute(
                    &dma_object,
                    hdr_offset + usize::from(hdr.header_size) + i * usize::from(hdr.entry_size)
                    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,
                )
                transmute_mut(&mut dma_object, (desc.imem_load_size + dmem_base) as usize)
            }?;

            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) as usize,
                )
            }?;

@@ -320,12 +316,11 @@ fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Re
                size: 0,
                flags: 2,
            };

            dmem_mapper.init_cmd = match cmd {
                FwsecCommand::Frts {
            if let FwsecCommand::Frts {
                frts_addr,
                frts_size,
                } => {
            } = cmd
            {
                frts_cmd.frts_region = FrtsRegion {
                    ver: 1,
                    hdr: u32::try_from(size_of::<FrtsRegion>())?,
@@ -333,11 +328,7 @@ fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Re
                    size: u32::try_from(frts_size >> 12)?,
                    ftype: NVFW_FRTS_CMD_REGION_TYPE_FB,
                };

                    NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS
            }
                FwsecCommand::Sb => NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB,
            };

            // Return early as we found and patched the DMEMMAPPER region.
            return Ok(Self(dma_object, PhantomData));