Skip to contentSkip to conversation

gpu: nova-core: vbios: harden various array accesses and refactor

PATCH Superseded Eliot Courtney 4 participants 30 messages Apr 14 – Aug 14

Subsystems (4)

v2 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v2 cover gpu: nova-core: vbios: harden various array accesses and refactor

We have some code that accesses arrays based on values from firmware. This patch series makes a bunch of those accesses more robust. This series only touches accesses that are not guaranteed to be safe by local invariants - some accesses are safe due to earlier checks and I haven't modified those.

This series also refactors and removes some code that can be simplified. In particular, it removes FwSecBiosBuilder. It also adds some more stringent checking for PCI-AT and FWSEC images so duplicate ones will result in an error.

---
Changes in v2:
- Add Joel's reviewed-by tags.
- Remove unnecessary code like falcon_data_offset from FwSecBiosBuilder
- Push offset handling into falcon_data_ptr (renamed)
- Simplify setup_falcon_data
- Add checking for spurious PCI-AT and FWSEC images.
- Remove FwSecBiosBuilder
- Link to v1: https://patch.msgid.link/[email protected]

---
Eliot Courtney (11):
gpu: nova-core: vbios: fix various cases of reading past BIOS_MAX_SCAN_LEN
gpu: nova-core: vbios: limit BitToken entry reads
gpu: nova-core: vbios: use checked ops and accesses in FwSecBiosImage::ucode
gpu: nova-core: vbios: use checked access in FwSecBiosImage::header
gpu: nova-core: vbios: use checked accesses in setup_falcon_data
gpu: nova-core: vbios: drop unused falcon_data_offset from FwSecBiosBuilder
gpu: nova-core: vbios: keep PmuLookupTable local in setup_falcon_data
gpu: nova-core: vbios: compute FWSEC-relative Falcon data offset
gpu: nova-core: vbios: simplify setup_falcon_data
gpu: nova-core: vbios: construct FwSecBiosImage directly from BIOS images
gpu: nova-core: vbios: reject extra PCI-AT and FWSEC images

 drivers/gpu/nova-core/vbios.rs | 299 +++++++++++++++++------------------------
 1 file changed, 126 insertions(+), 173 deletions(-)

---
base-commit: a7a080bb4236ebe577b6776d940d1717912ff6dd
change-id: 20260409-fix-vbios-d668e9c21d23

Best regards,

Signature · 1 line
Eliot Courtney <[email protected]>
#1 lore raw

PATCH v2 1/11 gpu: nova-core: vbios: fix various cases of reading past `BIOS_MAX_SCAN_LEN`

Fix various cases that allow reading past BIOS_MAX_SCAN_LEN when scanning the VBIOS.

Fix bug where read_more_at_offset would unnecessarily read more data. This happens when the window to read has some part cached and some part not. It would read len bytes instead of just the uncached portion, which could read past BIOS_MAX_SCAN_LEN.

Also add more checked arithmetic to catch potential overflows. read_bios_image_at_offset is called with a length from the VBIOS header, so we should be more defensive here.

Fixes 6fda04e7f0cd ("gpu: nova-core: vbios: Add base support for VBIOS construction and iteration")
---
 drivers/gpu/nova-core/vbios.rs | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)
drivers/gpu/nova-core/vbios.rs +8 -10
index ebda28e596c5..6de7e58e0da0 100644
@@ -132,17 +132,14 @@ fn read_more(&mut self, len: usize) -> Result {
 
     /// Read bytes at a specific offset, filling any gap.
     fn read_more_at_offset(&mut self, offset: usize, len: usize) -> Result {
-        if offset > BIOS_MAX_SCAN_LEN {
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
+
+        if end > BIOS_MAX_SCAN_LEN {
             dev_err!(self.dev, "Error: exceeded BIOS scan limit.\n");
             return Err(EINVAL);
         }
 
-        // If `offset` is beyond current data size, fill the gap first.
-        let current_len = self.data.len();
-        let gap_bytes = offset.saturating_sub(current_len);
-
-        // Now read the requested bytes at the offset.
-        self.read_more(gap_bytes + len)
+        self.read_more(end.saturating_sub(self.data.len()))
     }
 
     /// Read a BIOS image at a specific offset and create a [`BiosImage`] from it.
@@ -155,8 +152,9 @@ fn read_bios_image_at_offset(
         len: usize,
         context: &str,
     ) -> Result<BiosImage> {
+        let end = offset.checked_add(len).ok_or(EINVAL)?;
         let data_len = self.data.len();
-        if offset + len > data_len {
+        if end > data_len {
             self.read_more_at_offset(offset, len).inspect_err(|e| {
                 dev_err!(
                     self.dev,
@@ -167,7 +165,7 @@ fn read_bios_image_at_offset(
             })?;
         }
 
-        BiosImage::new(self.dev, &self.data[offset..offset + len]).inspect_err(|err| {
+        BiosImage::new(self.dev, &self.data[offset..end]).inspect_err(|err| {
             dev_err!(
                 self.dev,
                 "Failed to {} at offset {:#x}: {:?}\n",
@@ -189,7 +187,7 @@ fn next(&mut self) -> Option<Self::Item> {
             return None;
         }
 
-        if self.current_offset > BIOS_MAX_SCAN_LEN {
+        if self.current_offset >= BIOS_MAX_SCAN_LEN {
             dev_err!(self.dev, "Error: exceeded BIOS scan limit, stopping scan\n");
             return None;
         }
Signature · 1 line
2.53.0
#2 lore raw

PATCH v2 2/11 gpu: nova-core: vbios: limit `BitToken` entry reads

In reply to Eliot Courtney

If header.token_size is smaller than BitToken, then we currently can read past the end of image.base.data. Check that the token size is at least as big as BitToken.

Fixes dc70c6ae2441 ("gpu: nova-core: vbios: Add support to look up PMU table in FWSEC")
---
 drivers/gpu/nova-core/vbios.rs | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)
drivers/gpu/nova-core/vbios.rs +17 -17
index 6de7e58e0da0..de856000de23 100644
@@ -423,31 +423,31 @@ impl BitToken {
     /// Find a BIT token entry by BIT ID in a PciAtBiosImage
     fn from_id(image: &PciAtBiosImage, token_id: u8) -> Result<Self> {
         let header = &image.bit_header;
+        let entry_size = usize::from(header.token_size);
+
+        if entry_size < size_of::<BitToken>() {
+            return Err(EINVAL);
+        }
 
         // Offset to the first token entry
         let tokens_start = image.bit_offset + usize::from(header.header_size);
 
         for i in 0..usize::from(header.token_entries) {
-            let entry_offset = tokens_start + (i * usize::from(header.token_size));
-
-            // Make sure we don't go out of bounds
-            if entry_offset + usize::from(header.token_size) > image.base.data.len() {
-                return Err(EINVAL);
-            }
+            let entry_offset = tokens_start + (i * entry_size);
+            let entry = image
+                .base
+                .data
+                .get(entry_offset..)
+                .and_then(|data| data.get(..entry_size))
+                .ok_or(EINVAL)?;
 
             // Check if this token has the requested ID
-            if image.base.data[entry_offset] == token_id {
+            if entry[0] == token_id {
                 return Ok(BitToken {
-                    id: image.base.data[entry_offset],
-                    data_version: image.base.data[entry_offset + 1],
-                    data_size: u16::from_le_bytes([
-                        image.base.data[entry_offset + 2],
-                        image.base.data[entry_offset + 3],
-                    ]),
-                    data_offset: u16::from_le_bytes([
-                        image.base.data[entry_offset + 4],
-                        image.base.data[entry_offset + 5],
-                    ]),
+                    id: entry[0],
+                    data_version: entry[1],
+                    data_size: u16::from_le_bytes([entry[2], entry[3]]),
+                    data_offset: u16::from_le_bytes([entry[4], entry[5]]),
                 });
             }
         }
Signature · 1 line
2.53.0
#3 lore raw

PATCH v2 3/11 gpu: nova-core: vbios: use checked ops and accesses in `FwSecBiosImage::ucode`

In reply to Eliot Courtney

Use checked arithmetic and access for extracting the microcode since the offsets are firmware derived.

Fixes 47c4846e4319 ("gpu: nova-core: vbios: Add support for FWSEC ucode extraction")
---
 drivers/gpu/nova-core/vbios.rs | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)
drivers/gpu/nova-core/vbios.rs +12 -7
index de856000de23..632c8a90ea76 100644
@@ -1029,16 +1029,21 @@ pub(crate) fn header(&self) -> Result<FalconUCodeDesc> {
 
     /// Get the ucode data as a byte slice
     pub(crate) fn ucode(&self, desc: &FalconUCodeDesc) -> Result<&[u8]> {
-        let falcon_ucode_offset = self.falcon_ucode_offset;
-
         // The ucode data follows the descriptor.
-        let ucode_data_offset = falcon_ucode_offset + desc.size();
-        let size = usize::from_safe_cast(desc.imem_load_size() + desc.dmem_load_size());
+        let data = self
+            .base
+            .data
+            .get(self.falcon_ucode_offset..)
+            .ok_or(ERANGE)?;
+        let size = usize::from_safe_cast(
+            desc.imem_load_size()
+                .checked_add(desc.dmem_load_size())
+                .ok_or(ERANGE)?,
+        );
 
         // Get the data slice, checking bounds in a single operation.
-        self.base
-            .data
-            .get(ucode_data_offset..ucode_data_offset + size)
+        data.get(desc.size()..)
+            .and_then(|data| data.get(..size))
             .ok_or(ERANGE)
             .inspect_err(|_| {
                 dev_err!(
Signature · 1 line
2.53.0
#4 lore raw

PATCH v2 4/11 gpu: nova-core: vbios: use checked access in `FwSecBiosImage::header`

In reply to Eliot Courtney

Use checked access in FwSecBiosImage::header for getting the header version since the value is firmware derived.

Fixes 47c4846e4319 ("gpu: nova-core: vbios: Add support for FWSEC ucode extraction")
---
 drivers/gpu/nova-core/vbios.rs | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)
drivers/gpu/nova-core/vbios.rs +7 -10
index 632c8a90ea76..bc752d135cbf 100644
@@ -996,17 +996,14 @@ fn build(self) -> Result<FwSecBiosImage> {
 impl FwSecBiosImage {
     /// Get the FwSec header ([`FalconUCodeDesc`]).
     pub(crate) fn header(&self) -> Result<FalconUCodeDesc> {
-        // Get the falcon ucode offset that was found in setup_falcon_data.
-        let falcon_ucode_offset = self.falcon_ucode_offset;
+        let data = self
+            .base
+            .data
+            .get(self.falcon_ucode_offset..)
+            .ok_or(EINVAL)?;
 
-        // Read the first 4 bytes to get the version.
-        let hdr_bytes: [u8; 4] = self.base.data[falcon_ucode_offset..falcon_ucode_offset + 4]
-            .try_into()
-            .map_err(|_| EINVAL)?;
-        let hdr = u32::from_le_bytes(hdr_bytes);
-        let ver = (hdr & 0xff00) >> 8;
-
-        let data = self.base.data.get(falcon_ucode_offset..).ok_or(EINVAL)?;
+        // Read the version byte from the header.
+        let ver = data.get(1).copied().ok_or(EINVAL)?;
         match ver {
             2 => {
                 let v2 = FalconUCodeDescV2::from_bytes_copy_prefix(data)
Signature · 1 line
2.53.0
Reviewed-by on v2 4/11
#5 lore raw

Re: [PATCH v2 04/11] gpu: nova-core: vbios: use checked access in `FwSecBiosImage::header`

Quoted 28 lines · Eliot Courtney

Use checked access in FwSecBiosImage::header for getting the header version since the value is firmware derived.

Fixes 47c4846e4319 ("gpu: nova-core: vbios: Add support for FWSEC ucode extraction")
---
 drivers/gpu/nova-core/vbios.rs | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)
drivers/gpu/nova-core/vbios.rs +5 -5
index 632c8a90ea76..bc752d135cbf 100644
@@ -996,17 +996,14 @@ fn build(self) -> Result<FwSecBiosImage> {
 impl FwSecBiosImage {
     /// Get the FwSec header ([`FalconUCodeDesc`]).
     pub(crate) fn header(&self) -> Result<FalconUCodeDesc> {
-        // Get the falcon ucode offset that was found in setup_falcon_data.
-        let falcon_ucode_offset = self.falcon_ucode_offset;
+        let data = self
+            .base
+            .data
+            .get(self.falcon_ucode_offset..)
+            .ok_or(EINVAL)?;
 
-        // Read the first 4 bytes to get the version.
-        let hdr_bytes: [u8; 4] = self.base.data[falcon_ucode_offset..falcon_ucode_offset + 4]
-            .try_into()

drivers/gpu/nova-core/vbios.rs fn build(self) -> Result<FwSecBiosImage> { · line 1009

Quoted 10 lines
drivers/gpu/nova-core/vbios.rs +2 -5
-            .map_err(|_| EINVAL)?;
-        let hdr = u32::from_le_bytes(hdr_bytes);
-        let ver = (hdr & 0xff00) >> 8;
-
-        let data = self.base.data.get(falcon_ucode_offset..).ok_or(EINVAL)?;
+        // Read the version byte from the header.
+        let ver = data.get(1).copied().ok_or(EINVAL)?;
         match ver {
             2 => {
                 let v2 = FalconUCodeDescV2::from_bytes_copy_prefix(data)

sweet :)

Thanks.

#6 lore raw

Re: [PATCH v2 04/11] gpu: nova-core: vbios: use checked access in `FwSecBiosImage::header`

In reply to Eliot Courtney
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Unchecked slice indexing using a firmware-derived offset can panic and crash the kernel.
- [High] Unchecked subtraction on untrusted firmware data can underflow and panic. --

--- Patch [4]: [PATCH v2 04/11] gpu: nova-core: vbios: use checked access in FwSecBiosImage::header --- commit 90813931dc3fe4cfc37444ced769050fbff9b8d3
Author: Eliot Courtney <[email protected]>

gpu: nova-core: vbios: use checked access in FwSecBiosImage::header

This patch safely handles firmware-derived values in FwSecBiosImage::header by using checked access .get() instead of direct slice indexing.

Quoted 4 lines
drivers/gpu/nova-core/vbios.rs +0 -0
index 632c8a90ea765..bc752d135cbfd 100644

[ ... ]

drivers/gpu/nova-core/vbios.rs:FwSecBiosBuilder::setup_falcon_data() {
    ...
        if pmu_in_first_fwsec {
            self.pmu_lookup_table = Some(PmuLookupTable::new(
                &self.base.dev,
                &first_fwsec.base.data[offset..],
            )?);
        } else {
            self.pmu_lookup_table = Some(PmuLookupTable::new(
                &self.base.dev,
                &self.base.data[offset..],
            )?);
        }
    ...
}

[Severity: High]
This is a pre-existing issue, but since this patch addresses unchecked firmware accesses, I noticed these slice operations might lack upper bounds checks. If a malformed firmware provides a large, out-of-bounds pointer, could the offset exceed the length of the vector and cause a panic?

drivers/gpu/nova-core/vbios.rs:FwSecBiosBuilder::setup_falcon_data() {
    ...
            Ok(entry) => {
                let mut ucode_offset = usize::from_safe_cast(entry.data);
                ucode_offset -= pci_at_image.base.data.len();
    ...
}

[Severity: High]
This isn't a bug introduced by this patch, but is it possible for this subtraction on untrusted firmware data to underflow? If entry.data is smaller than the PCI-AT image length, could this cause a panic or lead to out-of-bounds accesses later?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
#7 lore raw

PATCH v2 5/11 gpu: nova-core: vbios: use checked accesses in `setup_falcon_data`

In reply to Eliot Courtney

Use checked arithmetic for ucode_offset in setup_falcon_data. This prevents a malformed firmware from causing a panic.

Fixes dc70c6ae2441 ("gpu: nova-core: vbios: Add support to look up PMU table in FWSEC")
---
 drivers/gpu/nova-core/vbios.rs | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)
drivers/gpu/nova-core/vbios.rs +9 -8
index bc752d135cbf..d8633e61178b 100644
@@ -955,14 +955,15 @@ fn setup_falcon_data(
             .find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)
         {
             Ok(entry) => {
-                let mut ucode_offset = usize::from_safe_cast(entry.data);
-                ucode_offset -= pci_at_image.base.data.len();
-                if ucode_offset < first_fwsec.base.data.len() {
-                    dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n");
-                    return Err(EINVAL);
-                }
-                ucode_offset -= first_fwsec.base.data.len();
-                self.falcon_ucode_offset = Some(ucode_offset);
+                self.falcon_ucode_offset = Some(
+                    usize::from_safe_cast(entry.data)
+                        .checked_sub(pci_at_image.base.data.len())
+                        .and_then(|o| o.checked_sub(first_fwsec.base.data.len()))
+                        .ok_or(EINVAL)
+                        .inspect_err(|_| {
+                            dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n");
+                        })?,
+                );
             }
             Err(e) => {
                 dev_err!(
Signature · 1 line
2.53.0
Reviewed-by on v2 5/11
#8 lore raw

Re: [PATCH v2 05/11] gpu: nova-core: vbios: use checked accesses in `setup_falcon_data`

Quoted 5 lines · Eliot Courtney

Use checked arithmetic for ucode_offset in setup_falcon_data. This prevents a malformed firmware from causing a panic.

Fixes dc70c6ae2441 ("gpu: nova-core: vbios: Add support to look up PMU table in FWSEC")

Thanks.

Quoted 33 lines
---
 drivers/gpu/nova-core/vbios.rs | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)
drivers/gpu/nova-core/vbios.rs +9 -8
index bc752d135cbf..d8633e61178b 100644
@@ -955,14 +955,15 @@ fn setup_falcon_data(
             .find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)
         {
             Ok(entry) => {
-                let mut ucode_offset = usize::from_safe_cast(entry.data);
-                ucode_offset -= pci_at_image.base.data.len();
-                if ucode_offset < first_fwsec.base.data.len() {
-                    dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n");
-                    return Err(EINVAL);
-                }
-                ucode_offset -= first_fwsec.base.data.len();
-                self.falcon_ucode_offset = Some(ucode_offset);
+                self.falcon_ucode_offset = Some(
+                    usize::from_safe_cast(entry.data)
+                        .checked_sub(pci_at_image.base.data.len())
+                        .and_then(|o| o.checked_sub(first_fwsec.base.data.len()))
+                        .ok_or(EINVAL)
+                        .inspect_err(|_| {
+                            dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n");
+                        })?,
+                );
             }
             Err(e) => {
                 dev_err!(
#9 lore raw

PATCH v2 6/11 gpu: nova-core: vbios: drop unused falcon_data_offset from FwSecBiosBuilder

In reply to Eliot Courtney

This is unused, so we can remove it.

---
 drivers/gpu/nova-core/vbios.rs | 5 -----
 1 file changed, 5 deletions(-)
drivers/gpu/nova-core/vbios.rs +0 -5
index d8633e61178b..d63af95eb642 100644
@@ -256,7 +256,6 @@ pub(crate) fn new(dev: &device::Device, bar0: &Bar0) -> Result<Vbios> {
                 Ok(BiosImageType::FwSec) => {
                     let fwsec = FwSecBiosBuilder {
                         base: image,
-                        falcon_data_offset: None,
                         pmu_lookup_table: None,
                         falcon_ucode_offset: None,
                     };
@@ -631,8 +630,6 @@ struct FwSecBiosBuilder {
     /// Once FwSecBiosBuilder 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.
@@ -934,8 +931,6 @@ fn setup_falcon_data(
             offset -= first_fwsec.base.data.len();
         }
 
-        self.falcon_data_offset = Some(offset);
-
         if pmu_in_first_fwsec {
             self.pmu_lookup_table = Some(PmuLookupTable::new(
                 &self.base.dev,
Signature · 1 line
2.53.0
Reviewed-by on v2 6/11
#10 lore raw

Re: [PATCH v2 06/11] gpu: nova-core: vbios: drop unused falcon_data_offset from FwSecBiosBuilder

Quoted 3 lines · Eliot Courtney

This is unused, so we can remove it.

Thanks.

Quoted 35 lines
---
 drivers/gpu/nova-core/vbios.rs | 5 -----
 1 file changed, 5 deletions(-)
drivers/gpu/nova-core/vbios.rs +0 -5
index d8633e61178b..d63af95eb642 100644
@@ -256,7 +256,6 @@ pub(crate) fn new(dev: &device::Device, bar0: &Bar0) -> Result<Vbios> {
                 Ok(BiosImageType::FwSec) => {
                     let fwsec = FwSecBiosBuilder {
                         base: image,
-                        falcon_data_offset: None,
                         pmu_lookup_table: None,
                         falcon_ucode_offset: None,
                     };
@@ -631,8 +630,6 @@ struct FwSecBiosBuilder {
     /// Once FwSecBiosBuilder 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.
@@ -934,8 +931,6 @@ fn setup_falcon_data(
             offset -= first_fwsec.base.data.len();
         }
 
-        self.falcon_data_offset = Some(offset);
-
         if pmu_in_first_fwsec {
             self.pmu_lookup_table = Some(PmuLookupTable::new(
                 &self.base.dev,
#11 lore raw

PATCH v2 7/11 gpu: nova-core: vbios: keep PmuLookupTable local in setup_falcon_data

In reply to Eliot Courtney

This does not need to be stored, so we can remove it.

---
 drivers/gpu/nova-core/vbios.rs | 25 ++++++-------------------
 1 file changed, 6 insertions(+), 19 deletions(-)
drivers/gpu/nova-core/vbios.rs +6 -19
index d63af95eb642..01f65d50cbb3 100644
@@ -256,7 +256,6 @@ pub(crate) fn new(dev: &device::Device, bar0: &Bar0) -> Result<Vbios> {
                 Ok(BiosImageType::FwSec) => {
                     let fwsec = FwSecBiosBuilder {
                         base: image,
-                        pmu_lookup_table: None,
                         falcon_ucode_offset: None,
                     };
                     if first_fwsec_image.is_none() {
@@ -630,8 +629,6 @@ struct FwSecBiosBuilder {
     /// Once FwSecBiosBuilder is constructed, the `falcon_ucode_offset` will be copied into a new
     /// [`FwSecBiosImage`].
     ///
-    /// 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>,
 }
@@ -931,24 +928,14 @@ fn setup_falcon_data(
             offset -= first_fwsec.base.data.len();
         }
 
-        if pmu_in_first_fwsec {
-            self.pmu_lookup_table = Some(PmuLookupTable::new(
-                &self.base.dev,
-                &first_fwsec.base.data[offset..],
-            )?);
+        let pmu_lookup_data = if pmu_in_first_fwsec {
+            &first_fwsec.base.data[offset..]
         } else {
-            self.pmu_lookup_table = Some(PmuLookupTable::new(
-                &self.base.dev,
-                &self.base.data[offset..],
-            )?);
-        }
+            self.base.data.get(offset..).ok_or(EINVAL)?
+        };
+        let pmu_lookup_table = PmuLookupTable::new(&self.base.dev, pmu_lookup_data)?;
 
-        match self
-            .pmu_lookup_table
-            .as_ref()
-            .ok_or(EINVAL)?
-            .find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)
-        {
+        match pmu_lookup_table.find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD) {
             Ok(entry) => {
                 self.falcon_ucode_offset = Some(
                     usize::from_safe_cast(entry.data)
Signature · 1 line
2.53.0
Reviewed-by on v2 7/11
#12 lore raw

Re: [PATCH v2 07/11] gpu: nova-core: vbios: keep PmuLookupTable local in setup_falcon_data

Quoted 1 line · Eliot Courtney

This does not need to be stored, so we can remove it.

Need more words/description, but patch is good.

Thanks.

Quoted 59 lines
---
 drivers/gpu/nova-core/vbios.rs | 25 ++++++-------------------
 1 file changed, 6 insertions(+), 19 deletions(-)
drivers/gpu/nova-core/vbios.rs +6 -19
index d63af95eb642..01f65d50cbb3 100644
@@ -256,7 +256,6 @@ pub(crate) fn new(dev: &device::Device, bar0: &Bar0) -> Result<Vbios> {
                 Ok(BiosImageType::FwSec) => {
                     let fwsec = FwSecBiosBuilder {
                         base: image,
-                        pmu_lookup_table: None,
                         falcon_ucode_offset: None,
                     };
                     if first_fwsec_image.is_none() {
@@ -630,8 +629,6 @@ struct FwSecBiosBuilder {
     /// Once FwSecBiosBuilder is constructed, the `falcon_ucode_offset` will be copied into a new
     /// [`FwSecBiosImage`].
     ///
-    /// 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>,
 }
@@ -931,24 +928,14 @@ fn setup_falcon_data(
             offset -= first_fwsec.base.data.len();
         }
 
-        if pmu_in_first_fwsec {
-            self.pmu_lookup_table = Some(PmuLookupTable::new(
-                &self.base.dev,
-                &first_fwsec.base.data[offset..],
-            )?);
+        let pmu_lookup_data = if pmu_in_first_fwsec {
+            &first_fwsec.base.data[offset..]
         } else {
-            self.pmu_lookup_table = Some(PmuLookupTable::new(
-                &self.base.dev,
-                &self.base.data[offset..],
-            )?);
-        }
+            self.base.data.get(offset..).ok_or(EINVAL)?
+        };
+        let pmu_lookup_table = PmuLookupTable::new(&self.base.dev, pmu_lookup_data)?;
 
-        match self
-            .pmu_lookup_table
-            .as_ref()
-            .ok_or(EINVAL)?
-            .find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)
-        {
+        match pmu_lookup_table.find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD) {
             Ok(entry) => {
                 self.falcon_ucode_offset = Some(
                     usize::from_safe_cast(entry.data)
#13 lore raw

PATCH v2 8/11 gpu: nova-core: vbios: compute FWSEC-relative Falcon data offset

In reply to Eliot Courtney

Push the computation of the falcon data offset into a helper function. The subtraction to create the offset should be checked, and by doing this the check can be folded into the existing check in falcon_data_ptr.

---
 drivers/gpu/nova-core/vbios.rs | 48 +++++++++++++++++-------------------------
 1 file changed, 19 insertions(+), 29 deletions(-)
drivers/gpu/nova-core/vbios.rs +19 -29
index 01f65d50cbb3..0c0e0402e715 100644
@@ -765,33 +765,29 @@ fn get_bit_token(&self, token_id: u8) -> Result<BitToken> {
         BitToken::from_id(self, token_id)
     }
 
-    /// Find the Falcon data pointer structure in the [`PciAtBiosImage`].
+    /// Find the Falcon data offset from the start of the FWSEC region.
     ///
-    /// This is just a 4 byte structure that contains a pointer to the Falcon data in the FWSEC
-    /// image.
-    fn falcon_data_ptr(&self) -> Result<u32> {
+    /// The BIT table contains a 4-byte pointer to the Falcon data. Testing shows this pointer
+    /// 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> {
         let token = self.get_bit_token(BIT_TOKEN_ID_FALCON_DATA)?;
-
-        // Make sure we don't go out of bounds
-        if usize::from(token.data_offset) + 4 > self.base.data.len() {
-            return Err(EINVAL);
-        }
-
-        // read the 4 bytes at the offset specified in the token
         let offset = usize::from(token.data_offset);
-        let bytes: [u8; 4] = self.base.data[offset..offset + 4].try_into().map_err(|_| {
-            dev_err!(self.base.dev, "Failed to convert data slice to array\n");
-            EINVAL
-        })?;
 
-        let data_ptr = u32::from_le_bytes(bytes);
+        // Read the 4-byte falcon data pointer at the offset specified in the token.
+        let data = &self.base.data;
+        let (ptr, _) = data
+            .get(offset..)
+            .and_then(u32::from_bytes_copy_prefix)
+            .ok_or(EINVAL)?;
 
-        if (usize::from_safe_cast(data_ptr)) < self.base.data.len() {
-            dev_err!(self.base.dev, "Falcon data pointer out of bounds\n");
-            return Err(EINVAL);
-        }
-
-        Ok(data_ptr)
+        usize::from_safe_cast(ptr)
+            .checked_sub(data.len())
+            .ok_or(EINVAL)
+            .inspect_err(|_| {
+                dev_err!(self.base.dev, "Falcon data pointer out of bounds\n");
+            })
     }
 }
 
@@ -908,15 +904,9 @@ fn setup_falcon_data(
         pci_at_image: &PciAtBiosImage,
         first_fwsec: &FwSecBiosBuilder,
     ) -> Result {
-        let mut offset = usize::from_safe_cast(pci_at_image.falcon_data_ptr()?);
+        let mut offset = pci_at_image.falcon_data_offset()?;
         let mut pmu_in_first_fwsec = false;
 
-        // The falcon data pointer assumes that the PciAt and FWSEC images
-        // are contiguous in memory. However, testing shows the EFI image sits in
-        // between them. So calculate the offset from the end of the PciAt image
-        // rather than the start of it. Compensate.
-        offset -= pci_at_image.base.data.len();
-
         // The offset is now from the start of the first Fwsec image, however
         // the offset points to a location in the second Fwsec image. Since
         // the fwsec images are contiguous, subtract the length of the first Fwsec
Signature · 1 line
2.53.0
Reviewed-by on v2 8/11
#14 lore raw

Re: [PATCH v2 08/11] gpu: nova-core: vbios: compute FWSEC-relative Falcon data offset

Quoted 15 lines · Eliot Courtney

Push the computation of the falcon data offset into a helper function. The subtraction to create the offset should be checked, and by doing this the check can be folded into the existing check in falcon_data_ptr.

---
 drivers/gpu/nova-core/vbios.rs | 48 +++++++++++++++++-------------------------
 1 file changed, 19 insertions(+), 29 deletions(-)
drivers/gpu/nova-core/vbios.rs +0 -0
index 01f65d50cbb3..0c0e0402e715 100644

drivers/gpu/nova-core/vbios.rs fn get_bit_token(&self, token_id: u8) -> Result<BitToken> { · line 768

Quoted 5 lines
drivers/gpu/nova-core/vbios.rs +1 -1
@@ -765,33 +765,29 @@ fn get_bit_token(&self, token_id: u8) -> Result<BitToken> {
         BitToken::from_id(self, token_id)
     }
 
-    /// Find the Falcon data pointer structure in the [`PciAtBiosImage`].
+    /// Find the Falcon data offset from the start of the FWSEC region.

The comment change is incorrect, this subtraction is just for normalizing. It basically normalizes the pointer wrt the PciAt image.

It is only after the following in the caller that we get the true offset within the FWSEC.

            offset -= first_fwsec.base.data.len();

I suggest, let us rename falcon_data_offset() to falcon_normalize_fwsec_offset() and update the comment above.

With these changed, please add:

Thanks.

Quoted 64 lines
drivers/gpu/nova-core/vbios.rs +18 -28
     ///
-    /// This is just a 4 byte structure that contains a pointer to the Falcon data in the FWSEC
-    /// image.
-    fn falcon_data_ptr(&self) -> Result<u32> {
+    /// The BIT table contains a 4-byte pointer to the Falcon data. Testing shows this pointer
+    /// 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> {
         let token = self.get_bit_token(BIT_TOKEN_ID_FALCON_DATA)?;
-
-        // Make sure we don't go out of bounds
-        if usize::from(token.data_offset) + 4 > self.base.data.len() {
-            return Err(EINVAL);
-        }
-
-        // read the 4 bytes at the offset specified in the token
         let offset = usize::from(token.data_offset);
-        let bytes: [u8; 4] = self.base.data[offset..offset + 4].try_into().map_err(|_| {
-            dev_err!(self.base.dev, "Failed to convert data slice to array\n");
-            EINVAL
-        })?;
 
-        let data_ptr = u32::from_le_bytes(bytes);
+        // Read the 4-byte falcon data pointer at the offset specified in the token.
+        let data = &self.base.data;
+        let (ptr, _) = data
+            .get(offset..)
+            .and_then(u32::from_bytes_copy_prefix)
+            .ok_or(EINVAL)?;
 
-        if (usize::from_safe_cast(data_ptr)) < self.base.data.len() {
-            dev_err!(self.base.dev, "Falcon data pointer out of bounds\n");
-            return Err(EINVAL);
-        }
-
-        Ok(data_ptr)
+        usize::from_safe_cast(ptr)
+            .checked_sub(data.len())
+            .ok_or(EINVAL)
+            .inspect_err(|_| {
+                dev_err!(self.base.dev, "Falcon data pointer out of bounds\n");
+            })
     }
 }
 
@@ -908,15 +904,9 @@ fn setup_falcon_data(
         pci_at_image: &PciAtBiosImage,
         first_fwsec: &FwSecBiosBuilder,
     ) -> Result {
-        let mut offset = usize::from_safe_cast(pci_at_image.falcon_data_ptr()?);
+        let mut offset = pci_at_image.falcon_data_offset()?;
         let mut pmu_in_first_fwsec = false;
 
-        // The falcon data pointer assumes that the PciAt and FWSEC images
-        // are contiguous in memory. However, testing shows the EFI image sits in
-        // between them. So calculate the offset from the end of the PciAt image
-        // rather than the start of it. Compensate.
-        offset -= pci_at_image.base.data.len();
-
         // The offset is now from the start of the first Fwsec image, however
         // the offset points to a location in the second Fwsec image. Since
         // the fwsec images are contiguous, subtract the length of the first Fwsec
#15 lore raw

Re: [PATCH v2 08/11] gpu: nova-core: vbios: compute FWSEC-relative Falcon data offset

Quoted 25 lines · Joel Fernandes
Quoted 15 lines · Eliot Courtney

Push the computation of the falcon data offset into a helper function. The subtraction to create the offset should be checked, and by doing this the check can be folded into the existing check in falcon_data_ptr.

---
 drivers/gpu/nova-core/vbios.rs | 48 +++++++++++++++++-------------------------
 1 file changed, 19 insertions(+), 29 deletions(-)
drivers/gpu/nova-core/vbios.rs +0 -0
index 01f65d50cbb3..0c0e0402e715 100644

drivers/gpu/nova-core/vbios.rs fn get_bit_token(&self, token_id: u8) -> Result<BitToken> { · line 768

Quoted 5 lines
drivers/gpu/nova-core/vbios.rs +1 -1
@@ -765,33 +765,29 @@ fn get_bit_token(&self, token_id: u8) -> Result<BitToken> {
         BitToken::from_id(self, token_id)
     }
 
-    /// Find the Falcon data pointer structure in the [`PciAtBiosImage`].
+    /// Find the Falcon data offset from the start of the FWSEC region.

The comment change is incorrect, this subtraction is just for normalizing. It basically normalizes the pointer wrt the PciAt image.

Quoted 6 lines

It is only after the following in the caller that we get the true offset within the FWSEC.

            offset -= first_fwsec.base.data.len();

I suggest, let us rename falcon_data_offset() to falcon_normalize_fwsec_offset() and update the comment above.

Thanks for your reviews! W.r.t. this, my understanding is that the layout is something like:

PCI-AT | Efi? | FWSEC | FWSEC

And that the falcon data pointer that we get out of PCI-AT starts off like this (indicated by ^):

^ PCI-AT | Efi? | FWSEC | FWSEC

But the actual "address space" it's in is:

^ PCI-AT | FWSEC | FWSEC

Because it doesn't count whatever images are between PCI-AT and the first FWSEC as part of that space. So by subtracting the PCI-AT size, we convert it to this logical space:

^ FWSEC | FWSEC

Based on the above understanding doesn't it make sense to say that falcon_data_offset transforms the pointer to be relative from the start of the FWSEC region? Once we subtract off the first fwsec image length, it's then relative to the second FWSEC image. Please LMK if I've missed something. We could also emphasise in the doc that the "FWSEC region" means the contiguous region defined by the first two FWSEC images. WDYT?

#16 lore raw

Re: [PATCH v2 08/11] gpu: nova-core: vbios: compute FWSEC-relative Falcon data offset

Quoted 53 lines · Eliot Courtney
Quoted 25 lines · Joel Fernandes
Quoted 15 lines · Eliot Courtney

Push the computation of the falcon data offset into a helper function. The subtraction to create the offset should be checked, and by doing this the check can be folded into the existing check in falcon_data_ptr.

---
 drivers/gpu/nova-core/vbios.rs | 48 +++++++++++++++++-------------------------
 1 file changed, 19 insertions(+), 29 deletions(-)
drivers/gpu/nova-core/vbios.rs +0 -0
index 01f65d50cbb3..0c0e0402e715 100644

drivers/gpu/nova-core/vbios.rs fn get_bit_token(&self, token_id: u8) -> Result<BitToken> { · line 768

Quoted 5 lines
drivers/gpu/nova-core/vbios.rs +1 -1
@@ -765,33 +765,29 @@ fn get_bit_token(&self, token_id: u8) -> Result<BitToken> {
         BitToken::from_id(self, token_id)
     }
 
-    /// Find the Falcon data pointer structure in the [`PciAtBiosImage`].
+    /// Find the Falcon data offset from the start of the FWSEC region.

The comment change is incorrect, this subtraction is just for normalizing. It basically normalizes the pointer wrt the PciAt image.

Quoted 6 lines

It is only after the following in the caller that we get the true offset within the FWSEC.

            offset -= first_fwsec.base.data.len();

I suggest, let us rename falcon_data_offset() to falcon_normalize_fwsec_offset() and update the comment above.

Thanks for your reviews! W.r.t. this, my understanding is that the layout is something like:

PCI-AT | Efi? | FWSEC | FWSEC

And that the falcon data pointer that we get out of PCI-AT starts off like this (indicated by ^):

^ PCI-AT | Efi? | FWSEC | FWSEC

But the actual "address space" it's in is:

^ PCI-AT | FWSEC | FWSEC

Because it doesn't count whatever images are between PCI-AT and the first FWSEC as part of that space. So by subtracting the PCI-AT size, we convert it to this logical space:

^ FWSEC | FWSEC

Quoted 7 lines

Based on the above understanding doesn't it make sense to say that falcon_data_offset transforms the pointer to be relative from the start of the FWSEC region? Once we subtract off the first fwsec image length, it's then relative to the second FWSEC image. Please LMK if I've missed something. We could also emphasise in the doc that the "FWSEC region" means the contiguous region defined by the first two FWSEC images. WDYT?

You did not miss anything, your explanation above is spot-on.

You could also keep your function name and add a comment on top of falcon_data_offset(). Something like "offset from the end of PCI-AT (i.e., the start of the combined FWSEC region)". Sounds good?

thanks,

--
Joel Fernandes

#17 lore raw

Re: [PATCH v2 08/11] gpu: nova-core: vbios: compute FWSEC-relative Falcon data offset

Quoted 64 lines · Joel Fernandes
Quoted 53 lines · Eliot Courtney
Quoted 25 lines · Joel Fernandes
Quoted 15 lines · Eliot Courtney

Push the computation of the falcon data offset into a helper function. The subtraction to create the offset should be checked, and by doing this the check can be folded into the existing check in falcon_data_ptr.

---
 drivers/gpu/nova-core/vbios.rs | 48 +++++++++++++++++-------------------------
 1 file changed, 19 insertions(+), 29 deletions(-)
drivers/gpu/nova-core/vbios.rs +0 -0
index 01f65d50cbb3..0c0e0402e715 100644

drivers/gpu/nova-core/vbios.rs fn get_bit_token(&self, token_id: u8) -> Result<BitToken> { · line 768

Quoted 5 lines
drivers/gpu/nova-core/vbios.rs +1 -1
@@ -765,33 +765,29 @@ fn get_bit_token(&self, token_id: u8) -> Result<BitToken> {
         BitToken::from_id(self, token_id)
     }
 
-    /// Find the Falcon data pointer structure in the [`PciAtBiosImage`].
+    /// Find the Falcon data offset from the start of the FWSEC region.

The comment change is incorrect, this subtraction is just for normalizing. It basically normalizes the pointer wrt the PciAt image.

Quoted 6 lines

It is only after the following in the caller that we get the true offset within the FWSEC.

            offset -= first_fwsec.base.data.len();

I suggest, let us rename falcon_data_offset() to falcon_normalize_fwsec_offset() and update the comment above.

Thanks for your reviews! W.r.t. this, my understanding is that the layout is something like:

PCI-AT | Efi? | FWSEC | FWSEC

And that the falcon data pointer that we get out of PCI-AT starts off like this (indicated by ^):

^ PCI-AT | Efi? | FWSEC | FWSEC

But the actual "address space" it's in is:

^ PCI-AT | FWSEC | FWSEC

Because it doesn't count whatever images are between PCI-AT and the first FWSEC as part of that space. So by subtracting the PCI-AT size, we convert it to this logical space:

^ FWSEC | FWSEC

Quoted 7 lines

Based on the above understanding doesn't it make sense to say that falcon_data_offset transforms the pointer to be relative from the start of the FWSEC region? Once we subtract off the first fwsec image length, it's then relative to the second FWSEC image. Please LMK if I've missed something. We could also emphasise in the doc that the "FWSEC region" means the contiguous region defined by the first two FWSEC images. WDYT?

Quoted 5 lines

You did not miss anything, your explanation above is spot-on.

You could also keep your function name and add a comment on top of falcon_data_offset(). Something like "offset from the end of PCI-AT (i.e., the start of the combined FWSEC region)". Sounds good?

Yerp SG. I realised I sent the next version without applying this feedback, sorry! But I do agree. I think we can strengthen it by saying the offset from the /combined/ FWSEC region like you suggest, and maybe mention that there may be an EFI after the end of PCI-AT.

thanks

#18 lore raw

PATCH v2 9/11 gpu: nova-core: vbios: simplify setup_falcon_data

In reply to Eliot Courtney

Remove pmu_in_first_fwsec and reorganize some code.

---
 drivers/gpu/nova-core/vbios.rs | 59 +++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 33 deletions(-)
drivers/gpu/nova-core/vbios.rs +26 -33
index 0c0e0402e715..d71ff5de794f 100644
@@ -904,48 +904,41 @@ fn setup_falcon_data(
         pci_at_image: &PciAtBiosImage,
         first_fwsec: &FwSecBiosBuilder,
     ) -> Result {
-        let mut offset = pci_at_image.falcon_data_offset()?;
-        let mut pmu_in_first_fwsec = false;
+        let offset = pci_at_image.falcon_data_offset()?;
 
-        // The offset is now from the start of the first Fwsec image, however
-        // the offset points to a location in the second Fwsec image. Since
-        // the fwsec images are contiguous, subtract the length of the first Fwsec
-        // image from the offset to get the offset to the start of the second
-        // Fwsec image.
-        if offset < first_fwsec.base.data.len() {
-            pmu_in_first_fwsec = true;
+        // 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.base.data.len() {
+            first_fwsec.base.data.get(offset..)
         } else {
-            offset -= first_fwsec.base.data.len();
-        }
-
-        let pmu_lookup_data = if pmu_in_first_fwsec {
-            &first_fwsec.base.data[offset..]
-        } else {
-            self.base.data.get(offset..).ok_or(EINVAL)?
+            self.base.data.get(offset - first_fwsec.base.data.len()..)
         };
-        let pmu_lookup_table = PmuLookupTable::new(&self.base.dev, pmu_lookup_data)?;
 
-        match pmu_lookup_table.find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD) {
-            Ok(entry) => {
-                self.falcon_ucode_offset = Some(
-                    usize::from_safe_cast(entry.data)
-                        .checked_sub(pci_at_image.base.data.len())
-                        .and_then(|o| o.checked_sub(first_fwsec.base.data.len()))
-                        .ok_or(EINVAL)
-                        .inspect_err(|_| {
-                            dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n");
-                        })?,
-                );
-            }
-            Err(e) => {
+        let pmu_lookup_table = pmu_lookup_data
+            .ok_or(EINVAL)
+            .and_then(|data| PmuLookupTable::new(&self.base.dev, data))?;
+
+        let entry = pmu_lookup_table
+            .find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)
+            .inspect_err(|e| {
                 dev_err!(
                     self.base.dev,
                     "PmuLookupTableEntry not found, error: {:?}\n",
                     e
                 );
-                return Err(EINVAL);
-            }
-        }
+            })?;
+
+        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.base.data.len()))
+            .ok_or(EINVAL)
+            .inspect_err(|_| {
+                dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n");
+            })?;
+
+        self.falcon_ucode_offset = Some(falcon_ucode_offset);
         Ok(())
     }
 
Signature · 1 line
2.53.0
Reviewed-by on v2 9/11
#19 lore raw

Re: [PATCH v2 09/11] gpu: nova-core: vbios: simplify setup_falcon_data

Quoted 1 line · Eliot Courtney

Remove pmu_in_first_fwsec and reorganize some code.

The patch itself is a nice improvement but the patch commit message needs more description [1]. Perhaps some of Alex's comments from here? [2]

[1]
https://kernel.org/doc/html/v6.19/process/submitting-patches.html#describe-changes
[2] https://lore.kernel.org/all/[email protected]/

With the commit message updated,

Thanks.

Quoted 86 lines
---
 drivers/gpu/nova-core/vbios.rs | 59 +++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 33 deletions(-)
drivers/gpu/nova-core/vbios.rs +26 -33
index 0c0e0402e715..d71ff5de794f 100644
@@ -904,48 +904,41 @@ fn setup_falcon_data(
         pci_at_image: &PciAtBiosImage,
         first_fwsec: &FwSecBiosBuilder,
     ) -> Result {
-        let mut offset = pci_at_image.falcon_data_offset()?;
-        let mut pmu_in_first_fwsec = false;
+        let offset = pci_at_image.falcon_data_offset()?;
 
-        // The offset is now from the start of the first Fwsec image, however
-        // the offset points to a location in the second Fwsec image. Since
-        // the fwsec images are contiguous, subtract the length of the first Fwsec
-        // image from the offset to get the offset to the start of the second
-        // Fwsec image.
-        if offset < first_fwsec.base.data.len() {
-            pmu_in_first_fwsec = true;
+        // 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.base.data.len() {
+            first_fwsec.base.data.get(offset..)
         } else {
-            offset -= first_fwsec.base.data.len();
-        }
-
-        let pmu_lookup_data = if pmu_in_first_fwsec {
-            &first_fwsec.base.data[offset..]
-        } else {
-            self.base.data.get(offset..).ok_or(EINVAL)?
+            self.base.data.get(offset - first_fwsec.base.data.len()..)
         };
-        let pmu_lookup_table = PmuLookupTable::new(&self.base.dev, pmu_lookup_data)?;
 
-        match pmu_lookup_table.find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD) {
-            Ok(entry) => {
-                self.falcon_ucode_offset = Some(
-                    usize::from_safe_cast(entry.data)
-                        .checked_sub(pci_at_image.base.data.len())
-                        .and_then(|o| o.checked_sub(first_fwsec.base.data.len()))
-                        .ok_or(EINVAL)
-                        .inspect_err(|_| {
-                            dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n");
-                        })?,
-                );
-            }
-            Err(e) => {
+        let pmu_lookup_table = pmu_lookup_data
+            .ok_or(EINVAL)
+            .and_then(|data| PmuLookupTable::new(&self.base.dev, data))?;
+
+        let entry = pmu_lookup_table
+            .find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)
+            .inspect_err(|e| {
                 dev_err!(
                     self.base.dev,
                     "PmuLookupTableEntry not found, error: {:?}\n",
                     e
                 );
-                return Err(EINVAL);
-            }
-        }
+            })?;
+
+        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.base.data.len()))
+            .ok_or(EINVAL)
+            .inspect_err(|_| {
+                dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n");
+            })?;
+
+        self.falcon_ucode_offset = Some(falcon_ucode_offset);
         Ok(())
     }
 
#20 lore raw

Re: [PATCH v2 09/11] gpu: nova-core: vbios: simplify setup_falcon_data

Quoted 12 lines · Joel Fernandes
Quoted 1 line · Eliot Courtney

Remove pmu_in_first_fwsec and reorganize some code.

The patch itself is a nice improvement but the patch commit message needs more description [1]. Perhaps some of Alex's comments from here? [2]

[1]
https://kernel.org/doc/html/v6.19/process/submitting-patches.html#describe-changes
[2] https://lore.kernel.org/all/[email protected]/

Thanks for finding the links, you're right, I was being lazy. Will update.

#21 lore raw

PATCH v2 10/11 gpu: nova-core: vbios: construct `FwSecBiosImage` directly from BIOS images

In reply to Eliot Courtney

FwSecBiosBuilder now only contains falcon_ucode_offset which just gets passed directly into FwSecBiosImage. Remove FwSecBiosBuilder and construct FwSecBiosImage directly, as a simplification.

---
 drivers/gpu/nova-core/vbios.rs | 98 +++++++++++++++++-------------------------
 1 file changed, 39 insertions(+), 59 deletions(-)
drivers/gpu/nova-core/vbios.rs +39 -59
index d71ff5de794f..5cc251c73800 100644
@@ -233,8 +233,8 @@ 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<FwSecBiosBuilder> = None;
-        let mut second_fwsec_image: Option<FwSecBiosBuilder> = None;
+        let mut first_fwsec_image: Option<BiosImage> = None;
+        let mut second_fwsec_image: Option<BiosImage> = None;
 
         // Parse all VBIOS images in the ROM
         for image_result in VbiosIterator::new(dev, bar0)? {
@@ -254,14 +254,10 @@ pub(crate) fn new(dev: &device::Device, bar0: &Bar0) -> Result<Vbios> {
                     pci_at_image = Some(PciAtBiosImage::try_from(image)?);
                 }
                 Ok(BiosImageType::FwSec) => {
-                    let fwsec = FwSecBiosBuilder {
-                        base: image,
-                        falcon_ucode_offset: None,
-                    };
                     if first_fwsec_image.is_none() {
-                        first_fwsec_image = Some(fwsec);
+                        first_fwsec_image = Some(image);
                     } else {
-                        second_fwsec_image = Some(fwsec);
+                        second_fwsec_image = Some(image);
                     }
                 }
                 _ => {
@@ -271,15 +267,23 @@ 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(mut second), Some(first), Some(pci_at)) =
+        if let (Some(second), Some(first), Some(pci_at)) =
             (second_fwsec_image, first_fwsec_image, pci_at_image)
         {
-            second
-                .setup_falcon_data(&pci_at, &first)
+            let fwsec_image = FwSecBiosImage::new(pci_at, first, second)
                 .inspect_err(|e| dev_err!(dev, "Falcon data setup failed: {:?}\n", e))?;
-            Ok(Vbios {
-                fwsec_image: second.build()?,
-            })
+
+            if cfg!(debug_assertions) {
+                // Print the desc header for debugging
+                let desc = fwsec_image.header()?;
+                dev_dbg!(
+                    fwsec_image.base.dev,
+                    "PmuLookupTableEntry desc: {:#?}\n",
+                    desc
+                );
+            }
+
+            Ok(Vbios { fwsec_image })
         } else {
             dev_err!(
                 dev,
@@ -621,18 +625,6 @@ struct NbsiBiosImage {
     // NBSI-specific fields can be added here in the future.
 }
 
-struct FwSecBiosBuilder {
-    base: BiosImage,
-    /// These are temporary fields that are used during the construction of the
-    /// [`FwSecBiosBuilder`].
-    ///
-    /// Once FwSecBiosBuilder is constructed, the `falcon_ucode_offset` will be copied into a new
-    /// [`FwSecBiosImage`].
-    ///
-    /// The offset of the Falcon ucode.
-    falcon_ucode_offset: Option<usize>,
-}
-
 /// The [`FwSecBiosImage`] structure contains the PMU table and the Falcon Ucode.
 ///
 /// The PMU table contains voltage/frequency tables as well as a pointer to the Falcon Ucode.
@@ -898,33 +890,34 @@ fn find_entry_by_type(&self, entry_type: u8) -> Result<PmuLookupTableEntry> {
     }
 }
 
-impl FwSecBiosBuilder {
-    fn setup_falcon_data(
-        &mut self,
-        pci_at_image: &PciAtBiosImage,
-        first_fwsec: &FwSecBiosBuilder,
-    ) -> Result {
+impl FwSecBiosImage {
+    /// Build the final `FwSecBiosImage` from the PCI-AT and FWSEC BIOS images
+    fn new(
+        pci_at_image: PciAtBiosImage,
+        first_fwsec: BiosImage,
+        second_fwsec: BiosImage,
+    ) -> Result<FwSecBiosImage> {
         let offset = pci_at_image.falcon_data_offset()?;
 
         // 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.base.data.len() {
-            first_fwsec.base.data.get(offset..)
+        let pmu_lookup_data = if offset < first_fwsec.data.len() {
+            first_fwsec.data.get(offset..)
         } else {
-            self.base.data.get(offset - first_fwsec.base.data.len()..)
+            second_fwsec.data.get(offset - first_fwsec.data.len()..)
         };
 
         let pmu_lookup_table = pmu_lookup_data
             .ok_or(EINVAL)
-            .and_then(|data| PmuLookupTable::new(&self.base.dev, data))?;
+            .and_then(|data| PmuLookupTable::new(&second_fwsec.dev, data))?;
 
         let entry = pmu_lookup_table
             .find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)
             .inspect_err(|e| {
                 dev_err!(
-                    self.base.dev,
+                    second_fwsec.dev,
                     "PmuLookupTableEntry not found, error: {:?}\n",
                     e
                 );
@@ -932,34 +925,21 @@ fn setup_falcon_data(
 
         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.base.data.len()))
+            .and_then(|o| o.checked_sub(first_fwsec.data.len()))
             .ok_or(EINVAL)
             .inspect_err(|_| {
-                dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n");
+                dev_err!(
+                    second_fwsec.dev,
+                    "Falcon Ucode offset not in second Fwsec.\n"
+                );
             })?;
 
-        self.falcon_ucode_offset = Some(falcon_ucode_offset);
-        Ok(())
+        Ok(FwSecBiosImage {
+            base: second_fwsec,
+            falcon_ucode_offset,
+        })
     }
 
-    /// Build the final FwSecBiosImage from this builder
-    fn build(self) -> Result<FwSecBiosImage> {
-        let ret = FwSecBiosImage {
-            base: self.base,
-            falcon_ucode_offset: self.falcon_ucode_offset.ok_or(EINVAL)?,
-        };
-
-        if cfg!(debug_assertions) {
-            // Print the desc header for debugging
-            let desc = ret.header()?;
-            dev_dbg!(ret.base.dev, "PmuLookupTableEntry desc: {:#?}\n", desc);
-        }
-
-        Ok(ret)
-    }
-}
-
-impl FwSecBiosImage {
     /// Get the FwSec header ([`FalconUCodeDesc`]).
     pub(crate) fn header(&self) -> Result<FalconUCodeDesc> {
         let data = self
Signature · 1 line
2.53.0
Reviewed-by on v2 10/11
#22 lore raw

Re: [PATCH v2 10/11] gpu: nova-core: vbios: construct `FwSecBiosImage` directly from BIOS images

Quoted 4 lines · Eliot Courtney

FwSecBiosBuilder now only contains falcon_ucode_offset which just gets passed directly into FwSecBiosImage. Remove FwSecBiosBuilder and construct FwSecBiosImage directly, as a simplification.

nice :) The reason for the builder object was, we wanted to have a 'calculate' phase and a 'build object now' phase to avoid the problem of partially constructed objects. However, as you showed we can accomplish that without an intermediary objects.

Thanks.

Quoted 177 lines
---
 drivers/gpu/nova-core/vbios.rs | 98 +++++++++++++++++-------------------------
 1 file changed, 39 insertions(+), 59 deletions(-)
drivers/gpu/nova-core/vbios.rs +39 -59
index d71ff5de794f..5cc251c73800 100644
@@ -233,8 +233,8 @@ 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<FwSecBiosBuilder> = None;
-        let mut second_fwsec_image: Option<FwSecBiosBuilder> = None;
+        let mut first_fwsec_image: Option<BiosImage> = None;
+        let mut second_fwsec_image: Option<BiosImage> = None;
 
         // Parse all VBIOS images in the ROM
         for image_result in VbiosIterator::new(dev, bar0)? {
@@ -254,14 +254,10 @@ pub(crate) fn new(dev: &device::Device, bar0: &Bar0) -> Result<Vbios> {
                     pci_at_image = Some(PciAtBiosImage::try_from(image)?);
                 }
                 Ok(BiosImageType::FwSec) => {
-                    let fwsec = FwSecBiosBuilder {
-                        base: image,
-                        falcon_ucode_offset: None,
-                    };
                     if first_fwsec_image.is_none() {
-                        first_fwsec_image = Some(fwsec);
+                        first_fwsec_image = Some(image);
                     } else {
-                        second_fwsec_image = Some(fwsec);
+                        second_fwsec_image = Some(image);
                     }
                 }
                 _ => {
@@ -271,15 +267,23 @@ 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(mut second), Some(first), Some(pci_at)) =
+        if let (Some(second), Some(first), Some(pci_at)) =
             (second_fwsec_image, first_fwsec_image, pci_at_image)
         {
-            second
-                .setup_falcon_data(&pci_at, &first)
+            let fwsec_image = FwSecBiosImage::new(pci_at, first, second)
                 .inspect_err(|e| dev_err!(dev, "Falcon data setup failed: {:?}\n", e))?;
-            Ok(Vbios {
-                fwsec_image: second.build()?,
-            })
+
+            if cfg!(debug_assertions) {
+                // Print the desc header for debugging
+                let desc = fwsec_image.header()?;
+                dev_dbg!(
+                    fwsec_image.base.dev,
+                    "PmuLookupTableEntry desc: {:#?}\n",
+                    desc
+                );
+            }
+
+            Ok(Vbios { fwsec_image })
         } else {
             dev_err!(
                 dev,
@@ -621,18 +625,6 @@ struct NbsiBiosImage {
     // NBSI-specific fields can be added here in the future.
 }
 
-struct FwSecBiosBuilder {
-    base: BiosImage,
-    /// These are temporary fields that are used during the construction of the
-    /// [`FwSecBiosBuilder`].
-    ///
-    /// Once FwSecBiosBuilder is constructed, the `falcon_ucode_offset` will be copied into a new
-    /// [`FwSecBiosImage`].
-    ///
-    /// The offset of the Falcon ucode.
-    falcon_ucode_offset: Option<usize>,
-}
-
 /// The [`FwSecBiosImage`] structure contains the PMU table and the Falcon Ucode.
 ///
 /// The PMU table contains voltage/frequency tables as well as a pointer to the Falcon Ucode.
@@ -898,33 +890,34 @@ fn find_entry_by_type(&self, entry_type: u8) -> Result<PmuLookupTableEntry> {
     }
 }
 
-impl FwSecBiosBuilder {
-    fn setup_falcon_data(
-        &mut self,
-        pci_at_image: &PciAtBiosImage,
-        first_fwsec: &FwSecBiosBuilder,
-    ) -> Result {
+impl FwSecBiosImage {
+    /// Build the final `FwSecBiosImage` from the PCI-AT and FWSEC BIOS images
+    fn new(
+        pci_at_image: PciAtBiosImage,
+        first_fwsec: BiosImage,
+        second_fwsec: BiosImage,
+    ) -> Result<FwSecBiosImage> {
         let offset = pci_at_image.falcon_data_offset()?;
 
         // 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.base.data.len() {
-            first_fwsec.base.data.get(offset..)
+        let pmu_lookup_data = if offset < first_fwsec.data.len() {
+            first_fwsec.data.get(offset..)
         } else {
-            self.base.data.get(offset - first_fwsec.base.data.len()..)
+            second_fwsec.data.get(offset - first_fwsec.data.len()..)
         };
 
         let pmu_lookup_table = pmu_lookup_data
             .ok_or(EINVAL)
-            .and_then(|data| PmuLookupTable::new(&self.base.dev, data))?;
+            .and_then(|data| PmuLookupTable::new(&second_fwsec.dev, data))?;
 
         let entry = pmu_lookup_table
             .find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)
             .inspect_err(|e| {
                 dev_err!(
-                    self.base.dev,
+                    second_fwsec.dev,
                     "PmuLookupTableEntry not found, error: {:?}\n",
                     e
                 );
@@ -932,34 +925,21 @@ fn setup_falcon_data(
 
         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.base.data.len()))
+            .and_then(|o| o.checked_sub(first_fwsec.data.len()))
             .ok_or(EINVAL)
             .inspect_err(|_| {
-                dev_err!(self.base.dev, "Falcon Ucode offset not in second Fwsec.\n");
+                dev_err!(
+                    second_fwsec.dev,
+                    "Falcon Ucode offset not in second Fwsec.\n"
+                );
             })?;
 
-        self.falcon_ucode_offset = Some(falcon_ucode_offset);
-        Ok(())
+        Ok(FwSecBiosImage {
+            base: second_fwsec,
+            falcon_ucode_offset,
+        })
     }
 
-    /// Build the final FwSecBiosImage from this builder
-    fn build(self) -> Result<FwSecBiosImage> {
-        let ret = FwSecBiosImage {
-            base: self.base,
-            falcon_ucode_offset: self.falcon_ucode_offset.ok_or(EINVAL)?,
-        };
-
-        if cfg!(debug_assertions) {
-            // Print the desc header for debugging
-            let desc = ret.header()?;
-            dev_dbg!(ret.base.dev, "PmuLookupTableEntry desc: {:#?}\n", desc);
-        }
-
-        Ok(ret)
-    }
-}
-
-impl FwSecBiosImage {
     /// Get the FwSec header ([`FalconUCodeDesc`]).
     pub(crate) fn header(&self) -> Result<FalconUCodeDesc> {
         let data = self
#23 lore raw

PATCH v2 11/11 gpu: nova-core: vbios: reject extra PCI-AT and FWSEC images

In reply to Eliot Courtney

Currently, these are silently overwritten. Instead, error if they appear twice in the VBIOS.

---
 drivers/gpu/nova-core/vbios.rs | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/gpu/nova-core/vbios.rs +8 -1
index 5cc251c73800..a9294b68ea77 100644
@@ -251,13 +251,20 @@ pub(crate) fn new(dev: &device::Device, bar0: &Bar0) -> Result<Vbios> {
             // Convert to a specific image type
             match BiosImageType::try_from(image.pcir.code_type) {
                 Ok(BiosImageType::PciAt) => {
+                    if pci_at_image.is_some() {
+                        dev_err!(dev, "More than 1 PCI-AT image found\n");
+                        return Err(EINVAL);
+                    }
                     pci_at_image = Some(PciAtBiosImage::try_from(image)?);
                 }
                 Ok(BiosImageType::FwSec) => {
                     if first_fwsec_image.is_none() {
                         first_fwsec_image = Some(image);
-                    } else {
+                    } else if second_fwsec_image.is_none() {
                         second_fwsec_image = Some(image);
+                    } else {
+                        dev_err!(dev, "More than 2 FwSec images found\n");
+                        return Err(EINVAL);
                     }
                 }
                 _ => {
Signature · 1 line
2.53.0
#24 lore raw

Re: [PATCH v2 11/11] gpu: nova-core: vbios: reject extra PCI-AT and FWSEC images

Quoted 2 lines · Eliot Courtney

Currently, these are silently overwritten. Instead, error if they appear twice in the VBIOS.

How do you know that there can only be one PCI-AT image or no more than 2 FWSEC images?

#25 lore raw

Re: [PATCH v2 11/11] gpu: nova-core: vbios: reject extra PCI-AT and FWSEC images

Quoted 9 lines · Timur Tabi
Quoted 2 lines · Eliot Courtney

Currently, these are silently overwritten. Instead, error if they appear twice in the VBIOS.

How do you know that there can only be one PCI-AT image or no more than 2 FWSEC images?

Also, which GPU is this extra PCI-AT observed on? When I wrote all this code, it was on GA102 and there was only one PCI-AT and 2 FWSEC.

Quoted 1 line
#26 lore raw

Re: [PATCH v2 11/11] gpu: nova-core: vbios: reject extra PCI-AT and FWSEC images

Quoted 11 lines · Joel Fernandes
Quoted 9 lines · Timur Tabi
Quoted 2 lines · Eliot Courtney

Currently, these are silently overwritten. Instead, error if they appear twice in the VBIOS.

How do you know that there can only be one PCI-AT image or no more than 2 FWSEC images?

Also, which GPU is this extra PCI-AT observed on? When I wrote all this code, it was on GA102 and there was only one PCI-AT and 2 FWSEC.

I think that it doesn't make sense for there to be more than one PCI-AT image. I haven't observed any, it's just that the current code will silently accept it. I think that we should explicitly define the behaviour here - erroring seems the most conservative to me, but other behaviours could be take the first or take the last.

This is more of a problem for FWSEC images, because the current code will take the first image as first_fwsec_image and the last image as second_fwsec_image, which means that if there are more than two, the falcon data offset will actually point to the wrong thing, since the code assumes that first and second fwsec image are contiguous for the purposes of the offset pointer space.

AFAICT, nouveau and openrm take the first PCI-AT and FWSEC images, but they use the first FWSEC image to adjust the offset and then just address directly into the whole VBIOS based on that. To match that behaviour I can update this this patch to change the nova behaviour to match - i.e. take first two FWSEC and first PCI-AT, instead of the current behaviour which is last PCI-AT and first+last FWSEC.

N.B. that the current code partially assumes that there are only two FWSEC images because it requires the falcon data pointer to be in the first or second one, and errors if it's after that.

WDYT?

#27 lore raw

Re: [PATCH v2 11/11] gpu: nova-core: vbios: reject extra PCI-AT and FWSEC images

Quoted 11 lines · Eliot Courtney
Quoted 10 lines · Joel Fernandes
Quoted 9 lines · Timur Tabi
Quoted 2 lines · Eliot Courtney

Currently, these are silently overwritten. Instead, error if they appear twice in the VBIOS.

How do you know that there can only be one PCI-AT image or no more than 2 FWSEC images?

Quoted 7 lines
Quoted 1 line

Also, which GPU is this extra PCI-AT observed on? When I wrote all this code, it was on GA102 and there was only one PCI-AT and 2 FWSEC.

I think that it doesn't make sense for there to be more than one PCI-AT image. I haven't observed any, it's just that the current code will silently accept it. I think that we should explicitly define the behaviour here - erroring seems the most conservative to me, but other behaviours could be take the first or take the last.

My opinion is I don't think it is useful to check for that, but I don't feel strongly either way. PciAt image type is from the standard PCI BIOS image format and even if it is overwritten, it will take the last one in current code afaics.

Quoted 7 lines

This is more of a problem for FWSEC images, because the current code will take the first image as first_fwsec_image and the last image as second_fwsec_image, which means that if there are more than two, the falcon data offset will actually point to the wrong thing, since the code assumes that first and second fwsec image are contiguous for the purposes of the offset pointer space.

Quoted 6 lines

AFAICT, nouveau and openrm take the first PCI-AT and FWSEC images, but they use the first FWSEC image to adjust the offset and then just address directly into the whole VBIOS based on that. To match that behaviour I can update this this patch to change the nova behaviour to match - i.e. take first two FWSEC and first PCI-AT, instead of the current behaviour which is last PCI-AT and first+last FWSEC.

My opinion is I don't see a benefit of changing it to that because everything including Turing is working with current code. Note that vbios parsing from nova is also legacy for Blackwell and later where the FSP handles this. And I'd rather not make non-functional changes and risk breaking working code.

Speaking of Turing, unless we have already done so, we should test this series on Turing as well. ISTR, Timur had some corner cases with this area of code.

Thanks.

#28 lore raw

Re: [PATCH v2 11/11] gpu: nova-core: vbios: reject extra PCI-AT and FWSEC images

Quoted 2 lines · Joel Fernandes

My opinion is I don't see a benefit of changing it to that because everything including Turing is working with current code.

Well, we can't really say that, because we've only tested Nova on a handful of systems. Adding code that detects and reports unexpected variations is probably a really good idea at this stage.

#29 lore raw

Re: [PATCH v2 11/11] gpu: nova-core: vbios: reject extra PCI-AT and FWSEC images

Quoted 7 lines · Timur Tabi
Quoted 2 lines · Joel Fernandes

My opinion is I don't see a benefit of changing it to that because everything including Turing is working with current code.

Well, we can't really say that, because we've only tested Nova on a handful of systems. Adding code that detects and reports unexpected variations is probably a really good idea at this stage.

I mean there are a lot of combinations of variations that are invalid, any code change should be justified, not random. That said, as I mentioned I am Ok either way if we want to check for this impossible condition.