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