[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <aD2oROKpaU8Bmyj-@pollux>
Date: Mon, 2 Jun 2025 15:33:56 +0200
From: Danilo Krummrich <dakr@...nel.org>
To: Alexandre Courbot <acourbot@...dia.com>
Cc: Miguel Ojeda <ojeda@...nel.org>, Alex Gaynor <alex.gaynor@...il.com>,
Boqun Feng <boqun.feng@...il.com>, Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <benno.lossin@...ton.me>,
Andreas Hindborg <a.hindborg@...nel.org>,
Alice Ryhl <aliceryhl@...gle.com>, Trevor Gross <tmgross@...ch.edu>,
David Airlie <airlied@...il.com>, Simona Vetter <simona@...ll.ch>,
Maarten Lankhorst <maarten.lankhorst@...ux.intel.com>,
Maxime Ripard <mripard@...nel.org>,
Thomas Zimmermann <tzimmermann@...e.de>,
John Hubbard <jhubbard@...dia.com>, Ben Skeggs <bskeggs@...dia.com>,
Joel Fernandes <joelagnelf@...dia.com>,
Timur Tabi <ttabi@...dia.com>, Alistair Popple <apopple@...dia.com>,
linux-kernel@...r.kernel.org, rust-for-linux@...r.kernel.org,
nouveau@...ts.freedesktop.org, dri-devel@...ts.freedesktop.org,
Shirish Baskaran <sbaskaran@...dia.com>
Subject: Re: [PATCH v4 16/20] nova-core: Add support for VBIOS ucode
extraction for boot
On Wed, May 21, 2025 at 03:45:11PM +0900, Alexandre Courbot wrote:
> +impl Vbios {
<snip>
> + pub(crate) fn fwsec_header(&self, pdev: &device::Device) -> Result<&FalconUCodeDescV3> {
> + self.fwsec_image.fwsec_header(pdev)
> + }
> +
> + pub(crate) fn fwsec_ucode(&self, pdev: &device::Device) -> Result<&[u8]> {
> + self.fwsec_image.fwsec_ucode(pdev, self.fwsec_header(pdev)?)
> + }
> +
> + pub(crate) fn fwsec_sigs(&self, pdev: &device::Device) -> Result<&[u8]> {
> + self.fwsec_image.fwsec_sigs(pdev, self.fwsec_header(pdev)?)
> + }
Can't we just implement Deref here? Why do we need this indirection?
> +impl PcirStruct {
> + fn new(pdev: &pci::Device, data: &[u8]) -> Result<Self> {
> + if data.len() < core::mem::size_of::<PcirStruct>() {
> + dev_err!(pdev.as_ref(), "Not enough data for PcirStruct\n");
> + return Err(EINVAL);
> + }
> +
> + let mut signature = [0u8; 4];
> + signature.copy_from_slice(&data[0..4]);
> +
> + // Signature should be "PCIR" (0x52494350) or "NPDS" (0x5344504e)
> + if &signature != b"PCIR" && &signature != b"NPDS" {
> + dev_err!(
> + pdev.as_ref(),
> + "Invalid signature for PcirStruct: {:?}\n",
> + signature
> + );
> + return Err(EINVAL);
> + }
> +
> + let mut class_code = [0u8; 3];
> + class_code.copy_from_slice(&data[13..16]);
> +
> + Ok(PcirStruct {
> + signature,
> + vendor_id: u16::from_le_bytes([data[4], data[5]]),
> + device_id: u16::from_le_bytes([data[6], data[7]]),
> + device_list_ptr: u16::from_le_bytes([data[8], data[9]]),
> + pci_data_struct_len: u16::from_le_bytes([data[10], data[11]]),
> + pci_data_struct_rev: data[12],
> + class_code,
> + image_len: u16::from_le_bytes([data[16], data[17]]),
> + vendor_rom_rev: u16::from_le_bytes([data[18], data[19]]),
> + code_type: data[20],
> + last_image: data[21],
> + max_runtime_image_len: u16::from_le_bytes([data[22], data[23]]),
> + })
> + }
> +
> + /// Check if this is the last image in the ROM
> + fn is_last(&self) -> bool {
> + self.last_image & LAST_IMAGE_BIT_MASK != 0
> + }
> +
> + /// Calculate image size in bytes
> + fn image_size_bytes(&self) -> Result<usize> {
> + if self.image_len > 0 {
Please make this check when creating the structure...
> + // Image size is in 512-byte blocks
...and make this a type invariant.
> + Ok(self.image_len as usize * 512)
It should also be a type invariant that this does not overflow.
The same applies to NpdeStruct.
> + } else {
> + Err(EINVAL)
> + }
> + }
> +}
<snip>
> + /// Try to find NPDE in the data, the NPDE is right after the PCIR.
> + fn find_in_data(
> + pdev: &pci::Device,
> + data: &[u8],
> + rom_header: &PciRomHeader,
> + pcir: &PcirStruct,
> + ) -> Option<Self> {
> + // Calculate the offset where NPDE might be located
> + // NPDE should be right after the PCIR structure, aligned to 16 bytes
> + let pcir_offset = rom_header.pci_data_struct_offset as usize;
> + let npde_start = (pcir_offset + pcir.pci_data_struct_len as usize + 0x0F) & !0x0F;
What's this magic offset and mask?
> +
> + // Check if we have enough data
> + if npde_start + 11 > data.len() {
'+ 11'?
> + dev_err!(pdev.as_ref(), "Not enough data for NPDE\n");
BiosImageBase declares this as "NVIDIA PCI Data Extension (optional)". If it's
really optional, why is this an error?
> + return None;
> + }
> +
> + // Try to create NPDE from the data
> + NpdeStruct::new(pdev, &data[npde_start..])
> + .inspect_err(|e| {
> + dev_err!(pdev.as_ref(), "Error creating NpdeStruct: {:?}\n", e);
> + })
> + .ok()
So, this returns None if it's a real error. This indicates that the return type
should just be Result<Option<Self>>.
> +struct FwSecBiosPartial {
Since this structure follows the builder pattern, can we please call it
FwSecBiosBuilder?
> + base: BiosImageBase,
> + // FWSEC-specific fields
> + // These are temporary fields that are used during the construction of
> + // the FwSecBiosPartial. Once FwSecBiosPartial is constructed, the
> + // falcon_ucode_offset will be copied into a new FwSecBiosImage.
> +
> + // The offset of the Falcon data from the start of Fwsec image
> + falcon_data_offset: Option<usize>,
> + // The PmuLookupTable starts at the offset of the falcon data pointer
> + pmu_lookup_table: Option<PmuLookupTable>,
> + // The offset of the Falcon ucode
> + falcon_ucode_offset: Option<usize>,
> +}
> +
> +struct FwSecBiosImage {
> + base: BiosImageBase,
> + // The offset of the Falcon ucode
> + falcon_ucode_offset: usize,
> +}
> +
> +// Convert from BiosImageBase to BiosImage
> +impl TryFrom<BiosImageBase> for BiosImage {
Why is this a TryFrom impl, instead of a regular constructor, i.e.
BiosImage::new()?
I don't think this is a canonical conversion.
> + type Error = Error;
> +
> + fn try_from(base: BiosImageBase) -> Result<Self> {
> + match base.pcir.code_type {
> + 0x00 => Ok(BiosImage::PciAt(base.try_into()?)),
> + 0x03 => Ok(BiosImage::Efi(EfiBiosImage { base })),
> + 0x70 => Ok(BiosImage::Nbsi(NbsiBiosImage { base })),
> + 0xE0 => Ok(BiosImage::FwSecPartial(FwSecBiosPartial {
> + base,
> + falcon_data_offset: None,
> + pmu_lookup_table: None,
> + falcon_ucode_offset: None,
> + })),
> + _ => Err(EINVAL),
> + }
> + }
> +}
<snip>
> +impl TryFrom<BiosImageBase> for PciAtBiosImage {
Same here.
> + type Error = Error;
> +
> + fn try_from(base: BiosImageBase) -> Result<Self> {
> + let data_slice = &base.data;
> + let (bit_header, bit_offset) = PciAtBiosImage::find_bit_header(data_slice)?;
> +
> + Ok(PciAtBiosImage {
> + base,
> + bit_header,
> + bit_offset,
> + })
> + }
> +}
<snip>
> +impl FwSecBiosImage {
> + fn new(pdev: &pci::Device, data: FwSecBiosPartial) -> Result<Self> {
Please add a method FwSecBiosBuilder::build() that returns an instance of
FwSecBiosImage instead.
Powered by blists - more mailing lists