Path: blob/master/drivers/gpu/nova-core/firmware/riscv.rs
29281 views
// SPDX-License-Identifier: GPL-2.012//! Support for firmware binaries designed to run on a RISC-V core. Such firmwares files have a3//! dedicated header.45use core::mem::size_of;67use kernel::device;8use kernel::firmware::Firmware;9use kernel::prelude::*;10use kernel::transmute::FromBytes;1112use crate::dma::DmaObject;13use crate::firmware::BinFirmware;1415/// Descriptor for microcode running on a RISC-V core.16#[repr(C)]17#[derive(Debug)]18struct RmRiscvUCodeDesc {19version: u32,20bootloader_offset: u32,21bootloader_size: u32,22bootloader_param_offset: u32,23bootloader_param_size: u32,24riscv_elf_offset: u32,25riscv_elf_size: u32,26app_version: u32,27manifest_offset: u32,28manifest_size: u32,29monitor_data_offset: u32,30monitor_data_size: u32,31monitor_code_offset: u32,32monitor_code_size: u32,33}3435// SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability.36unsafe impl FromBytes for RmRiscvUCodeDesc {}3738impl RmRiscvUCodeDesc {39/// Interprets the header of `bin_fw` as a [`RmRiscvUCodeDesc`] and returns it.40///41/// Fails if the header pointed at by `bin_fw` is not within the bounds of the firmware image.42fn new(bin_fw: &BinFirmware<'_>) -> Result<Self> {43let offset = bin_fw.hdr.header_offset as usize;4445bin_fw46.fw47.get(offset..offset + size_of::<Self>())48.and_then(Self::from_bytes_copy)49.ok_or(EINVAL)50}51}5253/// A parsed firmware for a RISC-V core, ready to be loaded and run.54#[expect(unused)]55pub(crate) struct RiscvFirmware {56/// Offset at which the code starts in the firmware image.57code_offset: u32,58/// Offset at which the data starts in the firmware image.59data_offset: u32,60/// Offset at which the manifest starts in the firmware image.61manifest_offset: u32,62/// Application version.63app_version: u32,64/// Device-mapped firmware image.65ucode: DmaObject,66}6768impl RiscvFirmware {69/// Parses the RISC-V firmware image contained in `fw`.70pub(crate) fn new(dev: &device::Device<device::Bound>, fw: &Firmware) -> Result<Self> {71let bin_fw = BinFirmware::new(fw)?;7273let riscv_desc = RmRiscvUCodeDesc::new(&bin_fw)?;7475let ucode = {76let start = bin_fw.hdr.data_offset as usize;77let len = bin_fw.hdr.data_size as usize;7879DmaObject::from_data(dev, fw.data().get(start..start + len).ok_or(EINVAL)?)?80};8182Ok(Self {83ucode,84code_offset: riscv_desc.monitor_code_offset,85data_offset: riscv_desc.monitor_data_offset,86manifest_offset: riscv_desc.manifest_offset,87app_version: riscv_desc.app_version,88})89}90}919293