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 pub(crate) struct RiscvFirmware { 61 /// Offset at which the code starts in the firmware image. 62 pub(crate) code_offset: u32, 63 /// Offset at which the data starts in the firmware image. 64 pub(crate) data_offset: u32, 65 /// Offset at which the manifest starts in the firmware image. 66 pub(crate) manifest_offset: u32, 67 /// Application version. 68 pub(crate) app_version: u32, 69 /// Device-mapped firmware image. 70 pub(crate) ucode: DmaObject, 71 } 72 73 impl RiscvFirmware { 74 /// Parses the RISC-V firmware image contained in `fw`. 75 pub(crate) fn new(dev: &device::Device<device::Bound>, fw: &Firmware) -> Result<Self> { 76 let bin_fw = BinFirmware::new(fw)?; 77 78 let riscv_desc = RmRiscvUCodeDesc::new(&bin_fw)?; 79 80 let ucode = { 81 let start = usize::from_safe_cast(bin_fw.hdr.data_offset); 82 let len = usize::from_safe_cast(bin_fw.hdr.data_size); 83 84 DmaObject::from_data(dev, fw.data().get(start..start + len).ok_or(EINVAL)?)? 85 }; 86 87 Ok(Self { 88 ucode, 89 code_offset: riscv_desc.monitor_code_offset, 90 data_offset: riscv_desc.monitor_data_offset, 91 manifest_offset: riscv_desc.manifest_offset, 92 app_version: riscv_desc.app_version, 93 }) 94 } 95 } 96