Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

John Hubbard and committed by
Alexandre Courbot
b3d24269 e10dcb9d

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