1
0

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: Daniel 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: Alexandre Courbot <acourbot@nvidia.com>
Message-ID: <20251104193756.57726-1-delcastillodelarosadaniel@gmail.com>
This commit is contained in:
Daniel del Castillo
2025-11-04 20:37:48 +01:00
committed by Alexandre Courbot
parent 173c99b85a
commit 473f778592

View File

@@ -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 @@ use kernel::{
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 @@ impl FirmwareDmaObject<FwsecFirmware, Unsigned> {
// 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,24 +316,19 @@ impl FirmwareDmaObject<FwsecFirmware, Unsigned> {
size: 0,
flags: 2,
};
dmem_mapper.init_cmd = match cmd {
FwsecCommand::Frts {
frts_addr,
frts_size,
} => {
frts_cmd.frts_region = FrtsRegion {
ver: 1,
hdr: u32::try_from(size_of::<FrtsRegion>())?,
addr: u32::try_from(frts_addr >> 12)?,
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,
};
if let FwsecCommand::Frts {
frts_addr,
frts_size,
} = cmd
{
frts_cmd.frts_region = FrtsRegion {
ver: 1,
hdr: u32::try_from(size_of::<FrtsRegion>())?,
addr: u32::try_from(frts_addr >> 12)?,
size: u32::try_from(frts_size >> 12)?,
ftype: NVFW_FRTS_CMD_REGION_TYPE_FB,
};
}
// Return early as we found and patched the DMEMMAPPER region.
return Ok(Self(dma_object, PhantomData));