Skip to content

Commit b3d2426

Browse files
johnhubbardGnurou
authored andcommitted
gpu: nova-core: firmware: move firmware image parsing code to firmware.rs
Up until now, only the GSP required parsing of its firmware headers. However, upcoming support for Hopper/Blackwell+ adds another firmware image (FMC), along with another format (ELF32). Therefore, the current ELF64 section parsing support needs to be moved up a level, so that both of the above can use it. There are no functional changes. This is pure code movement. Reviewed-by: Gary Guo <gary@garyguo.net> Signed-off-by: John Hubbard <jhubbard@nvidia.com> Acked-by: Danilo Krummrich <dakr@kernel.org> Link: https://patch.msgid.link/20260326013902.588242-8-jhubbard@nvidia.com [acourbot: use fuller prefix in commit message.] Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
1 parent e10dcb9 commit b3d2426

2 files changed

Lines changed: 92 additions & 87 deletions

File tree

drivers/gpu/nova-core/firmware.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,3 +457,91 @@ impl<const N: usize> ModInfoBuilder<N> {
457457
this.0
458458
}
459459
}
460+
461+
/// Ad-hoc and temporary module to extract sections from ELF images.
462+
///
463+
/// Some firmware images are currently packaged as ELF files, where sections names are used as keys
464+
/// to specific and related bits of data. Future firmware versions are scheduled to move away from
465+
/// that scheme before nova-core becomes stable, which means this module will eventually be
466+
/// removed.
467+
mod elf {
468+
use core::mem::size_of;
469+
470+
use kernel::{
471+
bindings,
472+
str::CStr,
473+
transmute::FromBytes, //
474+
};
475+
476+
/// Newtype to provide a [`FromBytes`] implementation.
477+
#[repr(transparent)]
478+
struct Elf64Hdr(bindings::elf64_hdr);
479+
// SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability.
480+
unsafe impl FromBytes for Elf64Hdr {}
481+
482+
#[repr(transparent)]
483+
struct Elf64SHdr(bindings::elf64_shdr);
484+
// SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability.
485+
unsafe impl FromBytes for Elf64SHdr {}
486+
487+
/// Tries to extract section with name `name` from the ELF64 image `elf`, and returns it.
488+
pub(super) fn elf64_section<'a, 'b>(elf: &'a [u8], name: &'b str) -> Option<&'a [u8]> {
489+
let hdr = &elf
490+
.get(0..size_of::<bindings::elf64_hdr>())
491+
.and_then(Elf64Hdr::from_bytes)?
492+
.0;
493+
494+
// Get all the section headers.
495+
let mut shdr = {
496+
let shdr_num = usize::from(hdr.e_shnum);
497+
let shdr_start = usize::try_from(hdr.e_shoff).ok()?;
498+
let shdr_end = shdr_num
499+
.checked_mul(size_of::<Elf64SHdr>())
500+
.and_then(|v| v.checked_add(shdr_start))?;
501+
502+
elf.get(shdr_start..shdr_end)
503+
.map(|slice| slice.chunks_exact(size_of::<Elf64SHdr>()))?
504+
};
505+
506+
// Get the strings table.
507+
let strhdr = shdr
508+
.clone()
509+
.nth(usize::from(hdr.e_shstrndx))
510+
.and_then(Elf64SHdr::from_bytes)?;
511+
512+
// Find the section which name matches `name` and return it.
513+
shdr.find(|&sh| {
514+
let Some(hdr) = Elf64SHdr::from_bytes(sh) else {
515+
return false;
516+
};
517+
518+
let Some(name_idx) = strhdr
519+
.0
520+
.sh_offset
521+
.checked_add(u64::from(hdr.0.sh_name))
522+
.and_then(|idx| usize::try_from(idx).ok())
523+
else {
524+
return false;
525+
};
526+
527+
// Get the start of the name.
528+
elf.get(name_idx..)
529+
.and_then(|nstr| CStr::from_bytes_until_nul(nstr).ok())
530+
// Convert into str.
531+
.and_then(|c_str| c_str.to_str().ok())
532+
// Check that the name matches.
533+
.map(|str| str == name)
534+
.unwrap_or(false)
535+
})
536+
// Return the slice containing the section.
537+
.and_then(|sh| {
538+
let hdr = Elf64SHdr::from_bytes(sh)?;
539+
let start = usize::try_from(hdr.0.sh_offset).ok()?;
540+
let end = usize::try_from(hdr.0.sh_size)
541+
.ok()
542+
.and_then(|sh_size| start.checked_add(sh_size))?;
543+
544+
elf.get(start..end)
545+
})
546+
}
547+
}

drivers/gpu/nova-core/firmware/gsp.rs

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ use kernel::{
1616
};
1717

1818
use crate::{
19-
firmware::riscv::RiscvFirmware,
19+
firmware::{
20+
elf,
21+
riscv::RiscvFirmware, //
22+
},
2023
gpu::{
2124
Architecture,
2225
Chipset, //
@@ -25,92 +28,6 @@ use crate::{
2528
num::FromSafeCast,
2629
};
2730

28-
/// Ad-hoc and temporary module to extract sections from ELF images.
29-
///
30-
/// Some firmware images are currently packaged as ELF files, where sections names are used as keys
31-
/// to specific and related bits of data. Future firmware versions are scheduled to move away from
32-
/// that scheme before nova-core becomes stable, which means this module will eventually be
33-
/// removed.
34-
mod elf {
35-
use kernel::{
36-
bindings,
37-
prelude::*,
38-
transmute::FromBytes, //
39-
};
40-
41-
/// Newtype to provide a [`FromBytes`] implementation.
42-
#[repr(transparent)]
43-
struct Elf64Hdr(bindings::elf64_hdr);
44-
// SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability.
45-
unsafe impl FromBytes for Elf64Hdr {}
46-
47-
#[repr(transparent)]
48-
struct Elf64SHdr(bindings::elf64_shdr);
49-
// SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability.
50-
unsafe impl FromBytes for Elf64SHdr {}
51-
52-
/// Tries to extract section with name `name` from the ELF64 image `elf`, and returns it.
53-
pub(super) fn elf64_section<'a, 'b>(elf: &'a [u8], name: &'b str) -> Option<&'a [u8]> {
54-
let hdr = &elf
55-
.get(0..size_of::<bindings::elf64_hdr>())
56-
.and_then(Elf64Hdr::from_bytes)?
57-
.0;
58-
59-
// Get all the section headers.
60-
let mut shdr = {
61-
let shdr_num = usize::from(hdr.e_shnum);
62-
let shdr_start = usize::try_from(hdr.e_shoff).ok()?;
63-
let shdr_end = shdr_num
64-
.checked_mul(size_of::<Elf64SHdr>())
65-
.and_then(|v| v.checked_add(shdr_start))?;
66-
67-
elf.get(shdr_start..shdr_end)
68-
.map(|slice| slice.chunks_exact(size_of::<Elf64SHdr>()))?
69-
};
70-
71-
// Get the strings table.
72-
let strhdr = shdr
73-
.clone()
74-
.nth(usize::from(hdr.e_shstrndx))
75-
.and_then(Elf64SHdr::from_bytes)?;
76-
77-
// Find the section which name matches `name` and return it.
78-
shdr.find(|&sh| {
79-
let Some(hdr) = Elf64SHdr::from_bytes(sh) else {
80-
return false;
81-
};
82-
83-
let Some(name_idx) = strhdr
84-
.0
85-
.sh_offset
86-
.checked_add(u64::from(hdr.0.sh_name))
87-
.and_then(|idx| usize::try_from(idx).ok())
88-
else {
89-
return false;
90-
};
91-
92-
// Get the start of the name.
93-
elf.get(name_idx..)
94-
.and_then(|nstr| CStr::from_bytes_until_nul(nstr).ok())
95-
// Convert into str.
96-
.and_then(|c_str| c_str.to_str().ok())
97-
// Check that the name matches.
98-
.map(|str| str == name)
99-
.unwrap_or(false)
100-
})
101-
// Return the slice containing the section.
102-
.and_then(|sh| {
103-
let hdr = Elf64SHdr::from_bytes(sh)?;
104-
let start = usize::try_from(hdr.0.sh_offset).ok()?;
105-
let end = usize::try_from(hdr.0.sh_size)
106-
.ok()
107-
.and_then(|sh_size| start.checked_add(sh_size))?;
108-
109-
elf.get(start..end)
110-
})
111-
}
112-
}
113-
11431
/// GSP firmware with 3-level radix page tables for the GSP bootloader.
11532
///
11633
/// The bootloader expects firmware to be mapped starting at address 0 in GSP's virtual address

0 commit comments

Comments
 (0)