Path: blob/master/drivers/gpu/nova-core/firmware/riscv.rs
50303 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 kernel::{6device,7firmware::Firmware,8prelude::*,9transmute::FromBytes, //10};1112use crate::{13dma::DmaObject,14firmware::BinFirmware,15num::FromSafeCast, //16};1718/// Descriptor for microcode running on a RISC-V core.19#[repr(C)]20#[derive(Debug)]21struct RmRiscvUCodeDesc {22version: u32,23bootloader_offset: u32,24bootloader_size: u32,25bootloader_param_offset: u32,26bootloader_param_size: u32,27riscv_elf_offset: u32,28riscv_elf_size: u32,29app_version: u32,30manifest_offset: u32,31manifest_size: u32,32monitor_data_offset: u32,33monitor_data_size: u32,34monitor_code_offset: u32,35monitor_code_size: u32,36}3738// SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability.39unsafe impl FromBytes for RmRiscvUCodeDesc {}4041impl RmRiscvUCodeDesc {42/// Interprets the header of `bin_fw` as a [`RmRiscvUCodeDesc`] and returns it.43///44/// Fails if the header pointed at by `bin_fw` is not within the bounds of the firmware image.45fn new(bin_fw: &BinFirmware<'_>) -> Result<Self> {46let offset = usize::from_safe_cast(bin_fw.hdr.header_offset);4748bin_fw49.fw50.get(offset..offset + size_of::<Self>())51.and_then(Self::from_bytes_copy)52.ok_or(EINVAL)53}54}5556/// A parsed firmware for a RISC-V core, ready to be loaded and run.57pub(crate) struct RiscvFirmware {58/// Offset at which the code starts in the firmware image.59pub(crate) code_offset: u32,60/// Offset at which the data starts in the firmware image.61pub(crate) data_offset: u32,62/// Offset at which the manifest starts in the firmware image.63pub(crate) manifest_offset: u32,64/// Application version.65pub(crate) app_version: u32,66/// Device-mapped firmware image.67pub(crate) ucode: DmaObject,68}6970impl RiscvFirmware {71/// Parses the RISC-V firmware image contained in `fw`.72pub(crate) fn new(dev: &device::Device<device::Bound>, fw: &Firmware) -> Result<Self> {73let bin_fw = BinFirmware::new(fw)?;7475let riscv_desc = RmRiscvUCodeDesc::new(&bin_fw)?;7677let ucode = {78let start = usize::from_safe_cast(bin_fw.hdr.data_offset);79let len = usize::from_safe_cast(bin_fw.hdr.data_size);8081DmaObject::from_data(dev, fw.data().get(start..start + len).ok_or(EINVAL)?)?82};8384Ok(Self {85ucode,86code_offset: riscv_desc.monitor_code_offset,87data_offset: riscv_desc.monitor_data_offset,88manifest_offset: riscv_desc.manifest_offset,89app_version: riscv_desc.app_version,90})91}92}939495