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 dma::Coherent, 9 firmware::Firmware, 10 prelude::*, 11 transmute::FromBytes, // 12 }; 13 14 use crate::{ 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 let end = offset.checked_add(size_of::<Self>()).ok_or(EINVAL)?; 49 50 bin_fw 51 .fw 52 .get(offset..end) 53 .and_then(Self::from_bytes_copy) 54 .ok_or(EINVAL) 55 } 56 } 57 58 /// A parsed firmware for a RISC-V core, ready to be loaded and run. 59 pub(crate) struct RiscvFirmware { 60 /// Offset at which the code starts in the firmware image. 61 pub(crate) code_offset: u32, 62 /// Offset at which the data starts in the firmware image. 63 pub(crate) data_offset: u32, 64 /// Offset at which the manifest starts in the firmware image. 65 pub(crate) manifest_offset: u32, 66 /// Application version. 67 pub(crate) app_version: u32, 68 /// Device-mapped firmware image. 69 pub(crate) ucode: Coherent<[u8]>, 70 } 71 72 impl RiscvFirmware { 73 /// Parses the RISC-V firmware image contained in `fw`. 74 pub(crate) fn new(dev: &device::Device<device::Bound>, fw: &Firmware) -> Result<Self> { 75 let bin_fw = BinFirmware::new(fw)?; 76 77 let riscv_desc = RmRiscvUCodeDesc::new(&bin_fw)?; 78 79 let ucode = { 80 let start = usize::from_safe_cast(bin_fw.hdr.data_offset); 81 let len = usize::from_safe_cast(bin_fw.hdr.data_size); 82 let end = start.checked_add(len).ok_or(EINVAL)?; 83 84 Coherent::from_slice(dev, fw.data().get(start..end).ok_or(EINVAL)?, GFP_KERNEL)? 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