The GSP bootloader is a small RISC-V firmware that is loaded by Booter onto the GSP core and is in charge of loading, validating, and starting the actual GSP firmware.
It is a regular binary firmware file containing a specific header. Create a type holding the DMA-mapped firmware as well as useful information extracted from the header, and hook it into our firmware structure for later use. The GSP bootloader is stored into the `GspFirmware` structure, since it is part of the GSP firmware package. This makes the `Firmware` structure empty, so remove it. Signed-off-by: Alexandre Courbot <acour...@nvidia.com> --- drivers/gpu/nova-core/firmware.rs | 18 +------ drivers/gpu/nova-core/firmware/gsp.rs | 7 +++ drivers/gpu/nova-core/firmware/riscv.rs | 89 +++++++++++++++++++++++++++++++++ drivers/gpu/nova-core/gpu.rs | 5 +- 4 files changed, 98 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs index cef910a7c2dc360139fafc2a01a050a9df40e45f..af7356a14def2ee92c3285878ea4de64eb48d344 100644 --- a/drivers/gpu/nova-core/firmware.rs +++ b/drivers/gpu/nova-core/firmware.rs @@ -15,11 +15,11 @@ use crate::dma::DmaObject; use crate::falcon::FalconFirmware; use crate::gpu; -use crate::gpu::Chipset; pub(crate) mod booter; pub(crate) mod fwsec; pub(crate) mod gsp; +pub(crate) mod riscv; pub(crate) const FIRMWARE_VERSION: &str = "535.113.01"; @@ -36,22 +36,6 @@ fn request_nv_firmware( .and_then(|path| firmware::Firmware::request(&path, dev)) } -/// Structure encapsulating the firmware blobs required for the GPU to operate. -#[expect(dead_code)] -pub(crate) struct Firmware { - bootloader: firmware::Firmware, -} - -impl Firmware { - pub(crate) fn new(dev: &device::Device, chipset: Chipset, ver: &str) -> Result<Firmware> { - let request = |name| request_nv_firmware(dev, chipset, name, ver); - - Ok(Firmware { - bootloader: request("bootloader")?, - }) - } -} - /// Structure used to describe some firmwares, notably FWSEC-FRTS. #[repr(C)] #[derive(Debug, Clone)] diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs index 9242e8ef6a0183cbfe5e75a3d6552ff528a2cedc..d25a21b42fc8b3987c861965e6ea56d929570b70 100644 --- a/drivers/gpu/nova-core/firmware/gsp.rs +++ b/drivers/gpu/nova-core/firmware/gsp.rs @@ -7,6 +7,7 @@ use kernel::scatterlist::{Owned, SGTable}; use crate::dma::DmaObject; +use crate::firmware::riscv::RiscvFirmware; use crate::gpu::{Architecture, Chipset}; use crate::gsp::GSP_PAGE_SIZE; @@ -127,6 +128,8 @@ pub(crate) struct GspFirmware { pub size: usize, /// Device-mapped GSP signatures matching the GPU's [`Chipset`]. signatures: DmaObject, + /// GSP bootloader, verifies the GSP firmware before loading and running it. + bootloader: RiscvFirmware, } impl GspFirmware { @@ -160,6 +163,9 @@ pub(crate) fn new<'a, 'b>( }) .map_err(|_| ENOMEM)?; + let bl = super::request_nv_firmware(dev, chipset, "bootloader", ver)?; + let bootloader = RiscvFirmware::new(dev, &bl)?; + Ok(try_pin_init!(Self { fw <- SGTable::new(dev, fw_vvec, DataDirection::ToDevice, GFP_KERNEL), level2 <- { @@ -202,6 +208,7 @@ pub(crate) fn new<'a, 'b>( }, size, signatures, + bootloader, })) } diff --git a/drivers/gpu/nova-core/firmware/riscv.rs b/drivers/gpu/nova-core/firmware/riscv.rs new file mode 100644 index 0000000000000000000000000000000000000000..b7eef29956995c49ab1466bb6a71a756731bf78a --- /dev/null +++ b/drivers/gpu/nova-core/firmware/riscv.rs @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Support for firmware binaries designed to run on a RISC-V core. Such firmwares files have a +//! dedicated header. + +use kernel::device; +use kernel::firmware::Firmware; +use kernel::prelude::*; +use kernel::transmute::FromBytes; + +use crate::dma::DmaObject; +use crate::firmware::BinFirmware; + +/// 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<Self> { + let offset = bin_fw.hdr.header_offset as usize; + + bin_fw + .fw + .get(offset..offset + size_of::<Self>()) + .and_then(Self::from_bytes_copy) + .ok_or(EINVAL) + } +} + +/// A parsed firmware for a RISC-V core, ready to be loaded and run. +#[expect(unused)] +pub(crate) struct RiscvFirmware { + /// Offset at which the code starts in the firmware image. + code_offset: u32, + /// Offset at which the data starts in the firmware image. + data_offset: u32, + /// Offset at which the manifest starts in the firmware image. + manifest_offset: u32, + /// Application version. + app_version: u32, + /// Device-mapped firmware image. + ucode: DmaObject, +} + +impl RiscvFirmware { + /// Parses the RISC-V firmware image contained in `fw`. + pub(crate) fn new(dev: &device::Device<device::Bound>, fw: &Firmware) -> Result<Self> { + let bin_fw = BinFirmware::new(fw)?; + + let riscv_desc = RmRiscvUCodeDesc::new(&bin_fw)?; + + let ucode = { + let start = bin_fw.hdr.data_offset as usize; + let len = bin_fw.hdr.data_size as usize; + + DmaObject::from_data(dev, fw.data().get(start..start + len).ok_or(EINVAL)?)? + }; + + 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, + }) + } +} diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 8505ee81c43e7628d1f099aff285244f8908c633..507af10502d5d3a073f220cce0a2e5fd0cc938b2 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -9,7 +9,7 @@ use crate::firmware::booter::{BooterFirmware, BooterKind}; use crate::firmware::fwsec::{FwsecCommand, FwsecFirmware}; use crate::firmware::gsp::GspFirmware; -use crate::firmware::{Firmware, FIRMWARE_VERSION}; +use crate::firmware::FIRMWARE_VERSION; use crate::gfw; use crate::regs; use crate::vbios::Vbios; @@ -179,7 +179,6 @@ pub(crate) struct Gpu { spec: Spec, /// MMIO mapping of PCI BAR 0 bar: Arc<Devres<Bar0>>, - fw: Firmware, /// System memory page required for flushing all pending GPU-side memory writes done through /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation). sysmem_flush: SysmemFlush, @@ -331,8 +330,6 @@ pub(crate) fn new<'a>( .inspect_err(|_| dev_err!(pdev.as_ref(), "GFW boot did not complete"))?; }, - fw <- Firmware::new(pdev.as_ref(), spec.chipset, FIRMWARE_VERSION)?, - sysmem_flush: SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?, gsp_falcon: Falcon::<Gsp>::new( -- 2.51.0