Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
6use core::mem::size_of;
7
8use kernel::{
9 device,
10 firmware::Firmware,
11 prelude::*,
12 transmute::FromBytes, //
13};
14
15use 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)]
24struct 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.
42unsafe impl FromBytes for RmRiscvUCodeDesc {}
43
44impl 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.
60pub(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
73impl 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}