mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
gpu: nova-core: vbios: parse structs via zerocopy
Replace the unsafe `kernel::transmute::FromBytes` trait implementation for the `FalconUCodeDescV3`, `PcirStruct`, `BitHeader`, `BitToken`, `NpdeStruct`, `PciRomHeader`, `PmuLookupTableEntry` and `PmuLookupTableHeader` structs with the derivable `zerocopy::FromBytes` trait. This change eliminates the manual unsafe implementations in favor of a derivable trait. When this trait is derived, validity checks are performed at compile time to ensure that the type can safely implement `FromBytes`. Suggested-by: Miguel Ojeda <ojeda@kernel.org> Link: https://github.com/Rust-for-Linux/linux/issues/1241 Signed-off-by: Nicolás Antinori <nico.antinori.7@gmail.com> Link: https://patch.msgid.link/20260629142007.269873-1-nico.antinori.7@gmail.com [acourbot: add `vbios:` prefix to commit title.] Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
This commit is contained in:
parent
23d66dbab8
commit
431f10ba13
|
|
@ -88,7 +88,7 @@ pub(crate) struct FalconUCodeDescV2 {
|
|||
|
||||
/// Structure used to describe some firmwares, notably FWSEC-FRTS.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, FromBytes)]
|
||||
pub(crate) struct FalconUCodeDescV3 {
|
||||
/// Header defined by `NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC*` in OpenRM.
|
||||
hdr: u32,
|
||||
|
|
@ -119,10 +119,6 @@ pub(crate) struct FalconUCodeDescV3 {
|
|||
_reserved: u16,
|
||||
}
|
||||
|
||||
// SAFETY: all bit patterns are valid for this type, and it doesn't use
|
||||
// interior mutability.
|
||||
unsafe impl FromBytes for FalconUCodeDescV3 {}
|
||||
|
||||
/// Enum wrapping the different versions of Falcon microcode descriptors.
|
||||
///
|
||||
/// This allows handling both V2 and V3 descriptor formats through a
|
||||
|
|
|
|||
|
|
@ -13,11 +13,8 @@
|
|||
register,
|
||||
sizes::SZ_4K,
|
||||
sync::aref::ARef,
|
||||
transmute::FromBytes,
|
||||
};
|
||||
|
||||
use zerocopy::FromBytes as _;
|
||||
|
||||
use crate::{
|
||||
driver::Bar0,
|
||||
firmware::{
|
||||
|
|
@ -359,7 +356,7 @@ pub(crate) fn fwsec_image(&self) -> &FwSecBiosImage {
|
|||
}
|
||||
|
||||
/// PCI Data Structure as defined in PCI Firmware Specification
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, FromBytes)]
|
||||
#[repr(C)]
|
||||
struct PcirStruct {
|
||||
/// PCI Data Structure signature ("PCIR" or "NPDS")
|
||||
|
|
@ -388,15 +385,12 @@ struct PcirStruct {
|
|||
max_runtime_image_len: u16,
|
||||
}
|
||||
|
||||
// SAFETY: all bit patterns are valid for `PcirStruct`.
|
||||
unsafe impl FromBytes for PcirStruct {}
|
||||
|
||||
impl PcirStruct {
|
||||
/// The bit in `last_image` that indicates the last image.
|
||||
const LAST_IMAGE_BIT_MASK: u8 = 0x80;
|
||||
|
||||
fn new(dev: &device::Device, data: &[u8]) -> Result<Self> {
|
||||
let (pcir, _) = PcirStruct::from_bytes_copy_prefix(data).ok_or(EINVAL)?;
|
||||
let (pcir, _) = PcirStruct::read_from_prefix(data).map_err(|_| EINVAL)?;
|
||||
|
||||
// Signature should be "PCIR" (0x52494350) or "NPDS" (0x5344504e).
|
||||
if &pcir.signature != b"PCIR" && &pcir.signature != b"NPDS" {
|
||||
|
|
@ -432,7 +426,7 @@ fn image_size_bytes(&self) -> usize {
|
|||
/// This is the head of the BIT table, that is used to locate the Falcon data. The BIT table (with
|
||||
/// its header) is in the [`PciAtBiosImage`] and the falcon data it is pointing to is in the
|
||||
/// [`FwSecBiosImage`].
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, FromBytes)]
|
||||
#[repr(C)]
|
||||
struct BitHeader {
|
||||
/// 0h: BIT Header Identifier (BMP=0x7FFF/BIT=0xB8FF)
|
||||
|
|
@ -451,12 +445,9 @@ struct BitHeader {
|
|||
checksum: u8,
|
||||
}
|
||||
|
||||
// SAFETY: all bit patterns are valid for `BitHeader`.
|
||||
unsafe impl FromBytes for BitHeader {}
|
||||
|
||||
impl BitHeader {
|
||||
fn new(data: &[u8]) -> Result<Self> {
|
||||
let (header, _) = BitHeader::from_bytes_copy_prefix(data).ok_or(EINVAL)?;
|
||||
let (header, _) = BitHeader::read_from_prefix(data).map_err(|_| EINVAL)?;
|
||||
|
||||
// Check header ID and signature
|
||||
if header.id != 0xB8FF || &header.signature != b"BIT\0" {
|
||||
|
|
@ -468,7 +459,7 @@ fn new(data: &[u8]) -> Result<Self> {
|
|||
}
|
||||
|
||||
/// BIT Token Entry: Records in the BIT table followed by the BIT header.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, FromBytes)]
|
||||
#[repr(C)]
|
||||
struct BitToken {
|
||||
/// 00h: Token identifier
|
||||
|
|
@ -481,9 +472,6 @@ struct BitToken {
|
|||
data_offset: u16,
|
||||
}
|
||||
|
||||
// SAFETY: all bit patterns are valid for `BitToken`.
|
||||
unsafe impl FromBytes for BitToken {}
|
||||
|
||||
impl BitToken {
|
||||
/// BIT token ID for Falcon data.
|
||||
const ID_FALCON_DATA: u8 = 0x70;
|
||||
|
|
@ -508,7 +496,7 @@ fn from_id(image: &PciAtBiosImage, token_id: u8) -> Result<Self> {
|
|||
.and_then(|data| data.get(..entry_size))
|
||||
.ok_or(EINVAL)?;
|
||||
|
||||
let (token, _) = BitToken::from_bytes_copy_prefix(entry).ok_or(EINVAL)?;
|
||||
let (token, _) = BitToken::read_from_prefix(entry).map_err(|_| EINVAL)?;
|
||||
|
||||
// Check if this token has the requested ID
|
||||
if token.id == token_id {
|
||||
|
|
@ -525,7 +513,7 @@ fn from_id(image: &PciAtBiosImage, token_id: u8) -> Result<Self> {
|
|||
///
|
||||
/// This header is at the beginning of every image in the set of images in the ROM. It contains a
|
||||
/// pointer to the PCI Data Structure which describes the image.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, FromBytes)]
|
||||
#[repr(C)]
|
||||
struct PciRomHeader {
|
||||
/// 00h: Signature (0xAA55)
|
||||
|
|
@ -536,13 +524,10 @@ struct PciRomHeader {
|
|||
pci_data_struct_offset: u16,
|
||||
}
|
||||
|
||||
// SAFETY: all bit patterns are valid for `PciRomHeader`.
|
||||
unsafe impl FromBytes for PciRomHeader {}
|
||||
|
||||
impl PciRomHeader {
|
||||
fn new(dev: &device::Device, data: &[u8]) -> Result<Self> {
|
||||
let (rom_header, _) = PciRomHeader::from_bytes_copy_prefix(data)
|
||||
.ok_or(EINVAL)
|
||||
let (rom_header, _) = PciRomHeader::read_from_prefix(data)
|
||||
.map_err(|_| EINVAL)
|
||||
.inspect_err(|_| dev_err!(dev, "Not enough data for ROM header\n"))?;
|
||||
|
||||
// Check for valid ROM signatures.
|
||||
|
|
@ -564,7 +549,7 @@ fn new(dev: &device::Device, data: &[u8]) -> Result<Self> {
|
|||
/// PCI Data Structure. It contains some fields that are redundant with the PCI Data Structure, but
|
||||
/// are needed for traversing the BIOS images. It is expected to be present in all BIOS images
|
||||
/// except for NBSI images.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, FromBytes)]
|
||||
#[repr(C)]
|
||||
struct NpdeStruct {
|
||||
/// 00h: Signature ("NPDE")
|
||||
|
|
@ -579,15 +564,12 @@ struct NpdeStruct {
|
|||
last_image: u8,
|
||||
}
|
||||
|
||||
// SAFETY: all bit patterns are valid for `NpdeStruct`.
|
||||
unsafe impl FromBytes for NpdeStruct {}
|
||||
|
||||
impl NpdeStruct {
|
||||
/// The bit in `last_image` that indicates the last image.
|
||||
const LAST_IMAGE_BIT_MASK: u8 = 0x80;
|
||||
|
||||
fn new(dev: &device::Device, data: &[u8]) -> Option<Self> {
|
||||
let (npde, _) = NpdeStruct::from_bytes_copy_prefix(data)?;
|
||||
let (npde, _) = NpdeStruct::read_from_prefix(data).ok()?;
|
||||
|
||||
// Signature should be "NPDE" (0x4544504E).
|
||||
if &npde.signature != b"NPDE" {
|
||||
|
|
@ -784,7 +766,7 @@ fn falcon_data_offset(&self, dev: &device::Device) -> Result<usize> {
|
|||
let data = &self.base.data;
|
||||
let (ptr, _) = data
|
||||
.get(offset..)
|
||||
.and_then(u32::from_bytes_copy_prefix)
|
||||
.and_then(|p| u32::read_from_prefix(p).ok())
|
||||
.ok_or(EINVAL)?;
|
||||
|
||||
usize::from_safe_cast(ptr)
|
||||
|
|
@ -814,6 +796,7 @@ fn try_from(base: BiosImage) -> Result<Self> {
|
|||
/// The [`PmuLookupTableEntry`] structure is a single entry in the [`PmuLookupTable`].
|
||||
///
|
||||
/// See the [`PmuLookupTable`] description for more information.
|
||||
#[derive(FromBytes)]
|
||||
#[repr(C, packed)]
|
||||
struct PmuLookupTableEntry {
|
||||
application_id: u8,
|
||||
|
|
@ -821,9 +804,6 @@ struct PmuLookupTableEntry {
|
|||
data: u32,
|
||||
}
|
||||
|
||||
// SAFETY: all bit patterns are valid for `PmuLookupTableEntry`.
|
||||
unsafe impl FromBytes for PmuLookupTableEntry {}
|
||||
|
||||
impl PmuLookupTableEntry {
|
||||
/// PMU lookup table application ID for firmware security license ucode.
|
||||
#[expect(dead_code)]
|
||||
|
|
@ -836,6 +816,7 @@ impl PmuLookupTableEntry {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(FromBytes)]
|
||||
struct PmuLookupTableHeader {
|
||||
version: u8,
|
||||
header_len: u8,
|
||||
|
|
@ -843,9 +824,6 @@ struct PmuLookupTableHeader {
|
|||
entry_count: u8,
|
||||
}
|
||||
|
||||
// SAFETY: all bit patterns are valid for `PmuLookupTableHeader`.
|
||||
unsafe impl FromBytes for PmuLookupTableHeader {}
|
||||
|
||||
/// The [`PmuLookupTableEntry`] structure is used to find the [`PmuLookupTableEntry`] for a given
|
||||
/// application ID.
|
||||
///
|
||||
|
|
@ -857,7 +835,7 @@ struct PmuLookupTable {
|
|||
|
||||
impl PmuLookupTable {
|
||||
fn new(dev: &device::Device, data: &[u8]) -> Result<Self> {
|
||||
let (header, _) = PmuLookupTableHeader::from_bytes_copy_prefix(data).ok_or(EINVAL)?;
|
||||
let (header, _) = PmuLookupTableHeader::read_from_prefix(data).map_err(|_| EINVAL)?;
|
||||
|
||||
let header_len = usize::from(header.header_len);
|
||||
let entry_len = usize::from(header.entry_len);
|
||||
|
|
@ -872,8 +850,8 @@ fn new(dev: &device::Device, data: &[u8]) -> Result<Self> {
|
|||
|
||||
let mut entries = KVVec::with_capacity(entry_count, GFP_KERNEL)?;
|
||||
for i in 0..entry_count {
|
||||
let (entry, _) = PmuLookupTableEntry::from_bytes_copy_prefix(&data[i * entry_len..])
|
||||
.ok_or(EINVAL)?;
|
||||
let (entry, _) = PmuLookupTableEntry::read_from_prefix(&data[i * entry_len..])
|
||||
.map_err(|_| EINVAL)?;
|
||||
entries.push(entry, GFP_KERNEL)?;
|
||||
}
|
||||
|
||||
|
|
@ -929,15 +907,11 @@ pub(crate) fn header(&self) -> Result<FalconUCodeDesc> {
|
|||
let ver = data.get(1).copied().ok_or(EINVAL)?;
|
||||
match ver {
|
||||
2 => {
|
||||
let v2 = FalconUCodeDescV2::read_from_prefix(data)
|
||||
.map_err(|_| EINVAL)?
|
||||
.0;
|
||||
let (v2, _) = FalconUCodeDescV2::read_from_prefix(data).map_err(|_| EINVAL)?;
|
||||
Ok(FalconUCodeDesc::V2(v2))
|
||||
}
|
||||
3 => {
|
||||
let v3 = FalconUCodeDescV3::from_bytes_copy_prefix(data)
|
||||
.ok_or(EINVAL)?
|
||||
.0;
|
||||
let (v3, _) = FalconUCodeDescV3::read_from_prefix(data).map_err(|_| EINVAL)?;
|
||||
Ok(FalconUCodeDesc::V3(v3))
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user