diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs index bd47ebbb013e..3aa0137cba53 100644 --- a/drivers/gpu/nova-core/firmware.rs +++ b/drivers/gpu/nova-core/firmware.rs @@ -365,29 +365,6 @@ struct BinHdr { // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. unsafe impl FromBytes for BinHdr {} -// A firmware blob starting with a `BinHdr`. -struct BinFirmware<'a> { - hdr: BinHdr, - fw: &'a [u8], -} - -impl<'a> BinFirmware<'a> { - /// Interpret `fw` as a firmware image starting with a [`BinHdr`], and returns the - /// corresponding [`BinFirmware`] that can be used to extract its payload. - fn new(fw: &'a firmware::Firmware) -> Result { - const BIN_MAGIC: u32 = 0x10de; - let fw = fw.data(); - - fw.get(0..size_of::()) - // Extract header. - .and_then(BinHdr::from_bytes_copy) - // Validate header. - .filter(|hdr| hdr.bin_magic == BIN_MAGIC) - .map(|hdr| Self { hdr, fw }) - .ok_or(EINVAL) - } -} - pub(crate) struct ModInfoBuilder(firmware::ModInfoBuilder); impl ModInfoBuilder { diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs index 99a302bae567..55a8c513e3a9 100644 --- a/drivers/gpu/nova-core/firmware/gsp.rs +++ b/drivers/gpu/nova-core/firmware/gsp.rs @@ -8,22 +8,24 @@ DataDirection, DmaAddress, // }, + firmware, prelude::*, scatterlist::{ Owned, SGTable, // }, + str::CString, }; use crate::{ firmware::{ - elf, riscv::RiscvFirmware, // + tlv::{ + request_tlv, // + Tlv, + }, }, - gpu::{ - Architecture, - Chipset, // - }, + gpu::Chipset, gsp::GSP_PAGE_SIZE, num::FromSafeCast, }; @@ -63,43 +65,26 @@ pub(crate) struct GspFirmware { } impl GspFirmware { - fn find_gsp_sigs_section(chipset: Chipset) -> &'static str { - match chipset.arch() { - Architecture::Turing if matches!(chipset, Chipset::TU116 | Chipset::TU117) => { - ".fwsignature_tu11x" - } - Architecture::Turing => ".fwsignature_tu10x", - Architecture::Ampere if chipset == Chipset::GA100 => ".fwsignature_ga100", - Architecture::Ampere => ".fwsignature_ga10x", - Architecture::Ada => ".fwsignature_ad10x", - Architecture::Hopper => ".fwsignature_gh10x", - Architecture::BlackwellGB10x => ".fwsignature_gb10x", - Architecture::BlackwellGB20x => ".fwsignature_gb20x", - } - } - /// Loads the GSP firmware binaries, map them into `dev`'s address-space, and creates the page /// tables expected by the GSP bootloader to load it. pub(crate) fn new<'a>( dev: &'a device::Device, chipset: Chipset, - ver: &'a str, ) -> impl PinInit + 'a { pin_init::pin_init_scope(move || { - let firmware = super::request_firmware(dev, chipset, "gsp", ver)?; + let firmware = request_tlv(dev, chipset, "gsp")?; + let tlv = Tlv::new(firmware.data())?; + dev_dbg!(dev, "loaded gsp firmware v{}\n", tlv.get_string(b"VERS")?); - let fw_section = elf::elf_section(firmware.data(), ".fwimage").ok_or(EINVAL)?; + let size = usize::from_safe_cast(tlv.get_u32(b"SIZE")?); + let mut fw_vvec = VVec::zeroed(size, GFP_KERNEL).map_err(|_| ENOMEM)?; - let size = fw_section.len(); + let chip_name = chipset.name(); + let file = tlv.get_string(b"FILE")?; + let filename = CString::try_from_fmt(fmt!("nvidia/{chip_name}/gsp/{file}"))?; + firmware::request_into_buf(&filename, dev, fw_vvec.as_mut_slice())?; - // Move the firmware into a vmalloc'd vector and map it into the device address - // space. - let fw_vvec = VVec::with_capacity(fw_section.len(), GFP_KERNEL) - .and_then(|mut v| { - v.extend_from_slice(fw_section, GFP_KERNEL)?; - Ok(v) - }) - .map_err(|_| ENOMEM)?; + let signatures = Coherent::from_slice(dev, tlv.get_bytes(b"SIGN")?, GFP_KERNEL)?; Ok(try_pin_init!(Self { fw <- SGTable::new(dev, fw_vvec, DataDirection::ToDevice, GFP_KERNEL), @@ -145,15 +130,9 @@ pub(crate) fn new<'a>( level0.into() }, size, - signatures: { - let sigs_section = Self::find_gsp_sigs_section(chipset); - - elf::elf_section(firmware.data(), sigs_section) - .ok_or(EINVAL) - .and_then(|data| Coherent::from_slice(dev, data, GFP_KERNEL))? - }, + signatures, bootloader: { - let bl = super::request_firmware(dev, chipset, "bootloader", ver)?; + let bl = request_tlv(dev, chipset, "gsp_bootloader")?; RiscvFirmware::new(dev, &bl)? }, diff --git a/drivers/gpu/nova-core/firmware/riscv.rs b/drivers/gpu/nova-core/firmware/riscv.rs index 2afa7f36404e..1403f05a7305 100644 --- a/drivers/gpu/nova-core/firmware/riscv.rs +++ b/drivers/gpu/nova-core/firmware/riscv.rs @@ -7,53 +7,10 @@ device, dma::Coherent, firmware::Firmware, - prelude::*, - transmute::FromBytes, // + prelude::*, // }; -use crate::{ - firmware::BinFirmware, - num::FromSafeCast, // -}; - -/// Descriptor for microcode running on a RISC-V core. -#[repr(C)] -#[derive(Debug)] -struct RmRiscvUCodeDesc { - version: u32, - bootloader_offset: u32, - bootloader_size: u32, - bootloader_param_offset: u32, - bootloader_param_size: u32, - riscv_elf_offset: u32, - riscv_elf_size: u32, - app_version: u32, - manifest_offset: u32, - manifest_size: u32, - monitor_data_offset: u32, - monitor_data_size: u32, - monitor_code_offset: u32, - monitor_code_size: u32, -} - -// SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. -unsafe impl FromBytes for RmRiscvUCodeDesc {} - -impl RmRiscvUCodeDesc { - /// Interprets the header of `bin_fw` as a [`RmRiscvUCodeDesc`] and returns it. - /// - /// Fails if the header pointed at by `bin_fw` is not within the bounds of the firmware image. - fn new(bin_fw: &BinFirmware<'_>) -> Result { - let offset = usize::from_safe_cast(bin_fw.hdr.header_offset); - let end = offset.checked_add(size_of::()).ok_or(EINVAL)?; - - bin_fw - .fw - .get(offset..end) - .and_then(Self::from_bytes_copy) - .ok_or(EINVAL) - } -} +use crate::firmware::tlv::Tlv; /// A parsed firmware for a RISC-V core, ready to be loaded and run. pub(crate) struct RiscvFirmware { @@ -72,24 +29,26 @@ pub(crate) struct RiscvFirmware { impl RiscvFirmware { /// Parses the RISC-V firmware image contained in `fw`. pub(crate) fn new(dev: &device::Device, fw: &Firmware) -> Result { - let bin_fw = BinFirmware::new(fw)?; + let tlv = Tlv::new(fw.data())?; + dev_dbg!( + dev, + "loaded gsp bootloader firmware v{}\n", + tlv.get_string(b"VERS")? + ); - let riscv_desc = RmRiscvUCodeDesc::new(&bin_fw)?; + let code_offset = tlv.get_u32(b"CDOF")?; + let data_offset = tlv.get_u32(b"DAOF")?; + let manifest_offset = tlv.get_u32(b"MFOF")?; + let app_version = tlv.get_u32(b"APPV")?; - let ucode = { - let start = usize::from_safe_cast(bin_fw.hdr.data_offset); - let len = usize::from_safe_cast(bin_fw.hdr.data_size); - let end = start.checked_add(len).ok_or(EINVAL)?; - - Coherent::from_slice(dev, fw.data().get(start..end).ok_or(EINVAL)?, GFP_KERNEL)? - }; + let ucode = Coherent::from_slice(dev, tlv.get_bytes(b"BLOB")?, GFP_KERNEL)?; Ok(Self { ucode, - code_offset: riscv_desc.monitor_code_offset, - data_offset: riscv_desc.monitor_data_offset, - manifest_offset: riscv_desc.manifest_offset, - app_version: riscv_desc.app_version, + code_offset, + data_offset, + manifest_offset, + app_version, }) } } diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs index 97f6e7ef4ead..e03700ee7bea 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -15,10 +15,7 @@ gsp::Gsp, Falcon, // }, - firmware::{ - gsp::GspFirmware, - FIRMWARE_VERSION, // - }, + firmware::gsp::GspFirmware, gsp::{ cmdq::Cmdq, commands, // @@ -45,7 +42,7 @@ pub(crate) fn boot( let dev = pdev.as_ref(); let hal = super::hal::gsp_hal(chipset); - let gsp_fw = KBox::pin_init(GspFirmware::new(dev, chipset, FIRMWARE_VERSION), GFP_KERNEL)?; + let gsp_fw = KBox::pin_init(GspFirmware::new(dev, chipset), GFP_KERNEL)?; // Perform the chipset-specific boot sequence, and retrieve the unload bundle. let unload_bundle = hal.boot(&self, &mut ctx, &gsp_fw)?.or_else(|| {