mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
gpu: nova-core: don't assume 64-bit firmware images
Introduce a single ELF format abstraction that ties each ELF header type to its matching section-header type. This keeps the shared section parser ready for upcoming ELF32 support and avoids mixing 32-bit and 64-bit ELF layouts by mistake. Signed-off-by: John Hubbard <jhubbard@nvidia.com> Reviewed-by: Eliot Courtney <ecourtney@nvidia.com> Link: https://patch.msgid.link/20260602032111.224790-8-jhubbard@nvidia.com Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
This commit is contained in:
parent
a5bf742bc2
commit
bd581ff381
|
|
@ -1,4 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
//! Contains structures and functions dedicated to the parsing, building and patching of firmwares
|
||||
//! to be loaded into a given execution unit.
|
||||
|
|
@ -467,17 +468,72 @@ mod elf {
|
|||
transmute::FromBytes, //
|
||||
};
|
||||
|
||||
/// Trait to abstract over ELF header differences.
|
||||
trait ElfHeader: FromBytes {
|
||||
fn shnum(&self) -> u16;
|
||||
fn shoff(&self) -> u64;
|
||||
fn shstrndx(&self) -> u16;
|
||||
}
|
||||
|
||||
/// Trait to abstract over ELF section-header differences.
|
||||
trait ElfSectionHeader: FromBytes {
|
||||
fn name(&self) -> u32;
|
||||
fn offset(&self) -> u64;
|
||||
fn size(&self) -> u64;
|
||||
}
|
||||
|
||||
/// Trait describing a matching ELF header and section-header format.
|
||||
trait ElfFormat {
|
||||
type Header: ElfHeader;
|
||||
type SectionHeader: ElfSectionHeader;
|
||||
}
|
||||
|
||||
/// Newtype to provide a [`FromBytes`] implementation.
|
||||
#[repr(transparent)]
|
||||
struct Elf64Hdr(bindings::elf64_hdr);
|
||||
// SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability.
|
||||
unsafe impl FromBytes for Elf64Hdr {}
|
||||
|
||||
impl ElfHeader for Elf64Hdr {
|
||||
fn shnum(&self) -> u16 {
|
||||
self.0.e_shnum
|
||||
}
|
||||
|
||||
fn shoff(&self) -> u64 {
|
||||
self.0.e_shoff
|
||||
}
|
||||
|
||||
fn shstrndx(&self) -> u16 {
|
||||
self.0.e_shstrndx
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
struct Elf64SHdr(bindings::elf64_shdr);
|
||||
// SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability.
|
||||
unsafe impl FromBytes for Elf64SHdr {}
|
||||
|
||||
impl ElfSectionHeader for Elf64SHdr {
|
||||
fn name(&self) -> u32 {
|
||||
self.0.sh_name
|
||||
}
|
||||
|
||||
fn offset(&self) -> u64 {
|
||||
self.0.sh_offset
|
||||
}
|
||||
|
||||
fn size(&self) -> u64 {
|
||||
self.0.sh_size
|
||||
}
|
||||
}
|
||||
|
||||
struct Elf64Format;
|
||||
|
||||
impl ElfFormat for Elf64Format {
|
||||
type Header = Elf64Hdr;
|
||||
type SectionHeader = Elf64SHdr;
|
||||
}
|
||||
|
||||
/// Returns a NULL-terminated string from the ELF image at `offset`.
|
||||
fn elf_str(elf: &[u8], offset: u64) -> Option<&str> {
|
||||
let idx = usize::try_from(offset).ok()?;
|
||||
|
|
@ -485,47 +541,49 @@ fn elf_str(elf: &[u8], offset: u64) -> Option<&str> {
|
|||
CStr::from_bytes_until_nul(bytes).ok()?.to_str().ok()
|
||||
}
|
||||
|
||||
/// Tries to extract section with name `name` from the ELF64 image `elf`, and returns it.
|
||||
pub(super) fn elf64_section<'a, 'b>(elf: &'a [u8], name: &'b str) -> Option<&'a [u8]> {
|
||||
let hdr = &elf
|
||||
.get(0..size_of::<bindings::elf64_hdr>())
|
||||
.and_then(Elf64Hdr::from_bytes)?
|
||||
.0;
|
||||
fn elf_section_generic<'a, F>(elf: &'a [u8], name: &str) -> Option<&'a [u8]>
|
||||
where
|
||||
F: ElfFormat,
|
||||
{
|
||||
let hdr = F::Header::from_bytes(elf.get(0..size_of::<F::Header>())?)?;
|
||||
|
||||
// Get all the section headers.
|
||||
let mut shdr = {
|
||||
let shdr_num = usize::from(hdr.e_shnum);
|
||||
let shdr_start = usize::try_from(hdr.e_shoff).ok()?;
|
||||
let shdr_end = shdr_num
|
||||
.checked_mul(size_of::<Elf64SHdr>())
|
||||
.and_then(|v| v.checked_add(shdr_start))?;
|
||||
let shdr_num = usize::from(hdr.shnum());
|
||||
let shdr_start = usize::try_from(hdr.shoff()).ok()?;
|
||||
let shdr_end = shdr_num
|
||||
.checked_mul(size_of::<F::SectionHeader>())
|
||||
.and_then(|v| v.checked_add(shdr_start))?;
|
||||
|
||||
elf.get(shdr_start..shdr_end)
|
||||
.map(|slice| slice.chunks_exact(size_of::<Elf64SHdr>()))?
|
||||
};
|
||||
// Get all the section headers as an iterator over byte chunks.
|
||||
let shdr_bytes = elf.get(shdr_start..shdr_end)?;
|
||||
let mut shdr_iter = shdr_bytes.chunks_exact(size_of::<F::SectionHeader>());
|
||||
|
||||
// Get the strings table.
|
||||
let strhdr = shdr
|
||||
let strhdr = shdr_iter
|
||||
.clone()
|
||||
.nth(usize::from(hdr.e_shstrndx))
|
||||
.and_then(Elf64SHdr::from_bytes)?;
|
||||
.nth(usize::from(hdr.shstrndx()))
|
||||
.and_then(F::SectionHeader::from_bytes)?;
|
||||
|
||||
// Find the section which name matches `name` and return it.
|
||||
shdr.find_map(|sh| {
|
||||
let hdr = Elf64SHdr::from_bytes(sh)?;
|
||||
let name_offset = strhdr.0.sh_offset.checked_add(u64::from(hdr.0.sh_name))?;
|
||||
shdr_iter.find_map(|sh_bytes| {
|
||||
let sh = F::SectionHeader::from_bytes(sh_bytes)?;
|
||||
let name_offset = strhdr.offset().checked_add(u64::from(sh.name()))?;
|
||||
let section_name = elf_str(elf, name_offset)?;
|
||||
|
||||
if section_name != name {
|
||||
return None;
|
||||
}
|
||||
|
||||
let start = usize::try_from(hdr.0.sh_offset).ok()?;
|
||||
let end = usize::try_from(hdr.0.sh_size)
|
||||
let start = usize::try_from(sh.offset()).ok()?;
|
||||
let end = usize::try_from(sh.size())
|
||||
.ok()
|
||||
.and_then(|sh_size| start.checked_add(sh_size))?;
|
||||
.and_then(|sz| start.checked_add(sz))?;
|
||||
|
||||
elf.get(start..end)
|
||||
})
|
||||
}
|
||||
|
||||
/// Tries to extract section with name `name` from the ELF64 image `elf`, and returns it.
|
||||
pub(super) fn elf64_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> {
|
||||
elf_section_generic::<Elf64Format>(elf, name)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user