public inbox for drm-ai-reviews@public-inbox.freedesktop.org
 help / color / mirror / Atom feed
From: Eliot Courtney <ecourtney@nvidia.com>
To: Danilo Krummrich <dakr@kernel.org>,
	Alice Ryhl <aliceryhl@google.com>,
	Alexandre Courbot <acourbot@nvidia.com>,
	David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>
Cc: John Hubbard <jhubbard@nvidia.com>,
	Alistair Popple <apopple@nvidia.com>,
	Timur Tabi <ttabi@nvidia.com>,
	nova-gpu@lists.linux.dev, rust-for-linux@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	Eliot Courtney <ecourtney@nvidia.com>
Subject: [PATCH v5 16/22] gpu: nova-core: vbios: use single logical block for the FWSEC section
Date: Mon, 25 May 2026 22:57:34 +0900	[thread overview]
Message-ID: <20260525-fix-vbios-v5-16-e5e455251537@nvidia.com> (raw)
In-Reply-To: <20260525-fix-vbios-v5-0-e5e455251537@nvidia.com>

Currently, FWSEC takes the first image and the last image. Treat the
first FWSEC image and all following image data as one logical block
for building the final FWSEC image. This avoids explicitly tracking
two FWSEC images.

Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/vbios.rs | 99 ++++++++++++++++--------------------------
 1 file changed, 37 insertions(+), 62 deletions(-)

diff --git a/drivers/gpu/nova-core/vbios.rs b/drivers/gpu/nova-core/vbios.rs
index 82811e42e858..5266e15793cf 100644
--- a/drivers/gpu/nova-core/vbios.rs
+++ b/drivers/gpu/nova-core/vbios.rs
@@ -84,7 +84,7 @@ struct VbiosIterator<'a> {
     /// progressively extends. It is used so that we do not re-read any contents that are already
     /// read as we use the cumulative length read so far, and re-read any gaps as we extend the
     /// length.
-    data: KVec<u8>,
+    data: KVVec<u8>,
     /// Current offset of the [`Iterator`].
     current_offset: usize,
     /// Indicate whether the last image has been found.
@@ -177,7 +177,7 @@ fn new(dev: &'a device::Device, bar0: &'a Bar0) -> Result<Self> {
         Ok(Self {
             dev,
             bar0,
-            data: KVec::new(),
+            data: KVVec::new(),
             current_offset: vbios_rom_offset(dev, bar0)?,
             last_found: false,
         })
@@ -315,8 +315,7 @@ impl Vbios {
     pub(crate) fn new(dev: &device::Device, bar0: &Bar0) -> Result<Vbios> {
         // Images to extract from iteration
         let mut pci_at_image: Option<PciAtBiosImage> = None;
-        let mut first_fwsec_image: Option<BiosImage> = None;
-        let mut second_fwsec_image: Option<BiosImage> = None;
+        let mut fwsec_section: Option<KVVec<u8>> = None;
 
         // Parse all VBIOS images in the ROM
         for image_result in VbiosIterator::new(dev, bar0)? {
@@ -330,6 +329,13 @@ pub(crate) fn new(dev: &device::Device, bar0: &Bar0) -> Result<Vbios> {
                 image.is_last()
             );
 
+            // Once we have found the first FWSEC image, grab all data after that as the FWSEC
+            // section. This is indexed as one logical block to build the final FWSEC image.
+            if let Some(data) = fwsec_section.as_mut() {
+                data.extend_from_slice(&image.data, GFP_KERNEL)?;
+                continue;
+            }
+
             // Convert to a specific image type
             match BiosImageType::try_from(image.pcir.code_type) {
                 Ok(BiosImageType::PciAt) => {
@@ -338,13 +344,7 @@ pub(crate) fn new(dev: &device::Device, bar0: &Bar0) -> Result<Vbios> {
                         pci_at_image = Some(PciAtBiosImage::try_from(image)?);
                     }
                 }
-                Ok(BiosImageType::FwSec) => {
-                    if first_fwsec_image.is_none() {
-                        first_fwsec_image = Some(image);
-                    } else {
-                        second_fwsec_image = Some(image);
-                    }
-                }
+                Ok(BiosImageType::FwSec) => fwsec_section = Some(image.data),
                 _ => {
                     // Ignore other image types or unknown types
                 }
@@ -352,10 +352,8 @@ pub(crate) fn new(dev: &device::Device, bar0: &Bar0) -> Result<Vbios> {
         }
 
         // Using all the images, setup the falcon data pointer in Fwsec.
-        if let (Some(second), Some(first), Some(pci_at)) =
-            (second_fwsec_image, first_fwsec_image, pci_at_image)
-        {
-            let fwsec_image = FwSecBiosImage::new(pci_at, first, second)
+        if let (Some(pci_at), Some(fwsec_section)) = (pci_at_image, fwsec_section) {
+            let fwsec_image = FwSecBiosImage::new(dev, pci_at, fwsec_section)
                 .inspect_err(|e| dev_err!(dev, "Falcon data setup failed: {:?}\n", e))?;
 
             Ok(Vbios { fwsec_image })
@@ -703,7 +701,10 @@ struct NbsiBiosImage {
 ///
 /// The PMU table contains voltage/frequency tables as well as a pointer to the Falcon Ucode.
 pub(crate) struct FwSecBiosImage {
-    base: BiosImage,
+    /// Used for logging.
+    dev: ARef<device::Device>,
+    /// FWSEC data.
+    data: KVVec<u8>,
     /// The offset of the Falcon ucode.
     falcon_ucode_offset: usize,
 }
@@ -713,8 +714,6 @@ pub(crate) struct FwSecBiosImage {
 /// A BiosImage struct is embedded into all image types and implements common operations.
 #[expect(dead_code)]
 struct BiosImage {
-    /// Used for logging.
-    dev: ARef<device::Device>,
     /// PCI ROM Expansion Header
     rom_header: PciRomHeader,
     /// PCI Data Structure
@@ -722,7 +721,7 @@ struct BiosImage {
     /// NVIDIA PCI Data Extension (optional)
     npde: Option<NpdeStruct>,
     /// Image data (includes ROM header and PCIR)
-    data: KVec<u8>,
+    data: KVVec<u8>,
 }
 
 impl BiosImage {
@@ -795,11 +794,10 @@ fn new(dev: &device::Device, data: &[u8]) -> Result<Self> {
         let npde = NpdeStruct::find_in_data(dev, data, &rom_header, &pcir);
 
         // Create a copy of the data.
-        let mut data_copy = KVec::new();
+        let mut data_copy = KVVec::new();
         data_copy.extend_from_slice(data, GFP_KERNEL)?;
 
         Ok(BiosImage {
-            dev: dev.into(),
             rom_header,
             pcir,
             npde,
@@ -837,7 +835,7 @@ fn get_bit_token(&self, token_id: u8) -> Result<BitToken> {
     /// treats the PCI-AT and FWSEC images as logically contiguous even when an EFI image sits in
     /// between them, so subtract the PCI-AT image size here to convert it to a FWSEC-relative
     /// offset.
-    fn falcon_data_offset(&self) -> Result<usize> {
+    fn falcon_data_offset(&self, dev: &device::Device) -> Result<usize> {
         let token = self.get_bit_token(BIT_TOKEN_ID_FALCON_DATA)?;
         let offset = usize::from(token.data_offset);
 
@@ -852,7 +850,7 @@ fn falcon_data_offset(&self) -> Result<usize> {
             .checked_sub(data.len())
             .ok_or(EINVAL)
             .inspect_err(|_| {
-                dev_err!(self.base.dev, "Falcon data pointer out of bounds\n");
+                dev_err!(dev, "Falcon data pointer out of bounds\n");
             })
     }
 }
@@ -942,59 +940,38 @@ fn find_entry_by_type(&self, entry_type: u8) -> Result<&PmuLookupTableEntry> {
 impl FwSecBiosImage {
     /// Build the final `FwSecBiosImage` from the PCI-AT and FWSEC BIOS images.
     fn new(
+        dev: &device::Device,
         pci_at_image: PciAtBiosImage,
-        first_fwsec: BiosImage,
-        second_fwsec: BiosImage,
+        data: KVVec<u8>,
     ) -> Result<FwSecBiosImage> {
-        let offset = pci_at_image.falcon_data_offset()?;
+        let offset = pci_at_image.falcon_data_offset(dev)?;
 
-        // The offset is from the start of the first FwSec image, but it
-        // may point into the second FwSec image. Treat the two FwSec images
-        // as contiguous here and subtract the first image length when the
-        // target lies in the second one.
-        let pmu_lookup_data = if offset < first_fwsec.data.len() {
-            first_fwsec.data.get(offset..)
-        } else {
-            second_fwsec.data.get(offset - first_fwsec.data.len()..)
-        }
-        .ok_or(EINVAL)?;
-
-        let pmu_lookup_table = PmuLookupTable::new(&second_fwsec.dev, pmu_lookup_data)?;
+        let pmu_lookup_data = data.get(offset..).ok_or(EINVAL)?;
+        let pmu_lookup_table = PmuLookupTable::new(dev, pmu_lookup_data)?;
 
         let entry = pmu_lookup_table
             .find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)
             .inspect_err(|e| {
-                dev_err!(
-                    second_fwsec.dev,
-                    "PmuLookupTableEntry not found, error: {:?}\n",
-                    e
-                );
+                dev_err!(dev, "PmuLookupTableEntry not found, error: {:?}\n", e);
             })?;
 
         let falcon_ucode_offset = usize::from_safe_cast(entry.data)
             .checked_sub(pci_at_image.base.data.len())
-            .and_then(|o| o.checked_sub(first_fwsec.data.len()))
             .ok_or(EINVAL)
             .inspect_err(|_| {
-                dev_err!(
-                    second_fwsec.dev,
-                    "Falcon Ucode offset not in second Fwsec.\n"
-                );
+                dev_err!(dev, "Falcon Ucode offset not in Fwsec.\n");
             })?;
 
         Ok(FwSecBiosImage {
-            base: second_fwsec,
+            dev: dev.into(),
+            data,
             falcon_ucode_offset,
         })
     }
 
     /// Get the FwSec header ([`FalconUCodeDesc`]).
     pub(crate) fn header(&self) -> Result<FalconUCodeDesc> {
-        let data = self
-            .base
-            .data
-            .get(self.falcon_ucode_offset..)
-            .ok_or(EINVAL)?;
+        let data = self.data.get(self.falcon_ucode_offset..).ok_or(EINVAL)?;
 
         // Read the version byte from the header.
         let ver = data.get(1).copied().ok_or(EINVAL)?;
@@ -1012,7 +989,7 @@ pub(crate) fn header(&self) -> Result<FalconUCodeDesc> {
                 Ok(FalconUCodeDesc::V3(v3))
             }
             _ => {
-                dev_err!(self.base.dev, "invalid fwsec firmware version: {:?}\n", ver);
+                dev_err!(self.dev, "invalid fwsec firmware version: {:?}\n", ver);
                 Err(EINVAL)
             }
         }
@@ -1027,15 +1004,14 @@ pub(crate) fn ucode(&self, desc: &FalconUCodeDesc) -> Result<&[u8]> {
         );
 
         // The ucode data follows the descriptor.
-        self.base
-            .data
+        self.data
             .get(self.falcon_ucode_offset..)
             .and_then(|data| data.get(desc.size()..))
             .and_then(|data| data.get(..size))
             .ok_or(ERANGE)
             .inspect_err(|_| {
                 dev_err!(
-                    self.base.dev,
+                    self.dev,
                     "fwsec ucode data not contained within BIOS bounds\n"
                 )
             })
@@ -1053,9 +1029,9 @@ pub(crate) fn sigs(&self, desc: &FalconUCodeDesc) -> Result<&[Bcrt30Rsa3kSignatu
         let sigs_size = sigs_count * core::mem::size_of::<Bcrt30Rsa3kSignature>();
 
         // Make sure the data is within bounds.
-        if sigs_data_offset + sigs_size > self.base.data.len() {
+        if sigs_data_offset + sigs_size > self.data.len() {
             dev_err!(
-                self.base.dev,
+                self.dev,
                 "fwsec signatures data not contained within BIOS bounds\n"
             );
             return Err(ERANGE);
@@ -1065,8 +1041,7 @@ pub(crate) fn sigs(&self, desc: &FalconUCodeDesc) -> Result<&[Bcrt30Rsa3kSignatu
         // sizeof::<Bcrt30Rsa3kSignature>()` is within the bounds of `data`.
         Ok(unsafe {
             core::slice::from_raw_parts(
-                self.base
-                    .data
+                self.data
                     .as_ptr()
                     .add(sigs_data_offset)
                     .cast::<Bcrt30Rsa3kSignature>(),

-- 
2.54.0


  parent reply	other threads:[~2026-05-25 13:59 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-25 13:57 [PATCH v5 00/22] gpu: nova-core: vbios: harden various array accesses and refactor Eliot Courtney
2026-05-25 13:57 ` [PATCH v5 01/22] gpu: nova-core: vbios: stop scanning at BIOS_MAX_SCAN_LEN Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 02/22] gpu: nova-core: vbios: use checked arithmetic for bios image range end Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 03/22] gpu: nova-core: vbios: avoid reading too far in read_more_at_offset Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 04/22] gpu: nova-core: vbios: read BitToken using FromBytes Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 05/22] gpu: nova-core: vbios: use checked ops and accesses in `FwSecBiosImage::ucode` Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 06/22] gpu: nova-core: vbios: use checked access in `FwSecBiosImage::header` Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 07/22] gpu: nova-core: vbios: use checked accesses in `setup_falcon_data` Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 08/22] gpu: nova-core: vbios: drop unused falcon_data_offset from FwSecBiosBuilder Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 09/22] gpu: nova-core: vbios: keep PmuLookupTable local in setup_falcon_data Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 10/22] gpu: nova-core: vbios: compute FWSEC-relative Falcon data offset Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 11/22] gpu: nova-core: vbios: simplify setup_falcon_data Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 12/22] gpu: nova-core: vbios: read PMU lookup entries using FromBytes Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 13/22] gpu: nova-core: vbios: store PMU lookup entries in a KVVec Eliot Courtney
2026-05-25 14:29   ` Danilo Krummrich
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 14/22] gpu: nova-core: vbios: construct `FwSecBiosImage` directly from BIOS images Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 15/22] gpu: nova-core: vbios: use the first PCI-AT image Eliot Courtney
2026-05-25 14:46   ` Danilo Krummrich
2026-05-25 18:02     ` Miguel Ojeda
2026-05-25 18:08       ` Danilo Krummrich
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` Eliot Courtney [this message]
2026-05-25 21:03   ` Claude review: gpu: nova-core: vbios: use single logical block for the FWSEC section Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 17/22] gpu: nova-core: vbios: use let-else in Vbios::new Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 18/22] gpu: nova-core: vbios: remove unnecessary fields in PciRomHeader Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 19/22] gpu: nova-core: vbios: drop unused image wrappers Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 20/22] gpu: nova-core: vbios: drop redundant TryFrom import Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 21/22] gpu: nova-core: vbios: move constants and functions to be associated Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 13:57 ` [PATCH v5 22/22] gpu: nova-core: vbios: remove unused rom_header field Eliot Courtney
2026-05-25 21:03   ` Claude review: " Claude Code Review Bot
2026-05-25 18:35 ` [PATCH v5 00/22] gpu: nova-core: vbios: harden various array accesses and refactor Danilo Krummrich
2026-05-25 18:37 ` Danilo Krummrich
2026-05-25 21:03 ` Claude review: " Claude Code Review Bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260525-fix-vbios-v5-16-e5e455251537@nvidia.com \
    --to=ecourtney@nvidia.com \
    --cc=acourbot@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=apopple@nvidia.com \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jhubbard@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nova-gpu@lists.linux.dev \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=simona@ffwll.ch \
    --cc=ttabi@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox