1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Support for firmware binaries designed to run on a RISC-V core. Such firmwares files have a 4 //! dedicated header. 5 6 use kernel::{ 7 device, 8 firmware::Firmware, 9 prelude::*, 10 transmute::FromBytes, // 11 }; 12 13 use crate::{ 14 dma::DmaObject, 15 firmware::BinFirmware, 16 num::FromSafeCast, // 17 }; 18 19 /// Descriptor for microcode running on a RISC-V core. 20 #[repr(C)] 21 #[derive(Debug)] 22 struct RmRiscvUCodeDesc { 23 version: u32, 24 bootloader_offset: u32, 25 bootloader_size: u32, 26 bootloader_param_offset: u32, 27 bootloader_param_size: u32, 28 riscv_elf_offset: u32, 29 riscv_elf_size: u32, 30 app_version: u32, 31 manifest_offset: u32, 32 manifest_size: u32, 33 monitor_data_offset: u32, 34 monitor_data_size: u32, 35 monitor_code_offset: u32, 36 monitor_code_size: u32, 37 } 38 39 // SAFETY: all bit patterns are valid for this type, and it doesn't use interior mutability. 40 unsafe impl FromBytes for RmRiscvUCodeDesc {} 41 42 impl RmRiscvUCodeDesc { 43 /// Interprets the header of `bin_fw` as a [`RmRiscvUCodeDesc`] and returns it. 44 /// 45 /// Fails if the header pointed at by `bin_fw` is not within the bounds of the firmware image. 46 fn new(bin_fw: &BinFirmware<'_>) -> Result<Self> { 47 let offset = usize::from_safe_cast(bin_fw.hdr.header_offset); 48 49 bin_fw 50 .fw 51 .get(offset..offset + size_of::<Self>()) 52 .and_then(Self::from_bytes_copy) 53 .ok_or(EINVAL) 54 } 55 } 56 57 /// A parsed firmware for a RISC-V core, ready to be loaded and run. 58 pub(crate) struct RiscvFirmware { 59 /// Offset at which the code starts in the firmware image. 60 pub(crate) code_offset: u32, 61 /// Offset at which the data starts in the firmware image. 62 pub(crate) data_offset: u32, 63 /// Offset at which the manifest starts in the firmware image. 64 pub(crate) manifest_offset: u32, 65 /// Application version. 66 pub(crate) app_version: u32, 67 /// Device-mapped firmware image. 68 pub(crate) ucode: DmaObject, 69 } 70 71 impl RiscvFirmware { 72 /// Parses the RISC-V firmware image contained in `fw`. 73 pub(crate) fn new(dev: &device::Device<device::Bound>, fw: &Firmware) -> Result<Self> { 74 let bin_fw = BinFirmware::new(fw)?; 75 76 let riscv_desc = RmRiscvUCodeDesc::new(&bin_fw)?; 77 78 let ucode = { 79 let start = usize::from_safe_cast(bin_fw.hdr.data_offset); 80 let len = usize::from_safe_cast(bin_fw.hdr.data_size); 81 82 DmaObject::from_data(dev, fw.data().get(start..start + len).ok_or(EINVAL)?)? 83 }; 84 85 Ok(Self { 86 ucode, 87 code_offset: riscv_desc.monitor_code_offset, 88 data_offset: riscv_desc.monitor_data_offset, 89 manifest_offset: riscv_desc.manifest_offset, 90 app_version: riscv_desc.app_version, 91 }) 92 } 93 } 94