earlgrey_cw310/otbn.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! Components for collections of Hardware Accelerators.
//!
//! Usage
//! -----
//! ```rust
//! let _mux_otbn = crate::otbn::AccelMuxComponent::new(&peripherals.otbn)
//! .finalize(otbn_mux_component_static!());
//!
//! peripherals.otbn.initialise(
//! dynamic_deferred_caller
//! .register(&peripherals.otbn)
//! .unwrap(), // Unwrap fail = dynamic deferred caller out of slots
//! );
//! ```
use core::mem::MaybeUninit;
use kernel::component::Component;
use lowrisc::otbn::Otbn;
use lowrisc::virtual_otbn::{MuxAccel, VirtualMuxAccel};
#[macro_export]
macro_rules! otbn_mux_component_static {
() => {{
kernel::static_buf!(lowrisc::virtual_otbn::MuxAccel<'static>)
}};
}
#[macro_export]
macro_rules! otbn_component_static {
() => {{
kernel::static_buf!(lowrisc::virtual_otbn::VirtualMuxAccel<'static>)
}};
}
pub struct AccelMuxComponent {
otbn: &'static Otbn<'static>,
}
impl AccelMuxComponent {
pub fn new(otbn: &'static Otbn<'static>) -> AccelMuxComponent {
AccelMuxComponent { otbn }
}
}
impl Component for AccelMuxComponent {
type StaticInput = &'static mut MaybeUninit<MuxAccel<'static>>;
type Output = &'static MuxAccel<'static>;
fn finalize(self, s: Self::StaticInput) -> Self::Output {
s.write(MuxAccel::new(self.otbn))
}
}
pub struct OtbnComponent {
mux_otbn: &'static MuxAccel<'static>,
}
impl OtbnComponent {
pub fn new(mux_otbn: &'static MuxAccel<'static>) -> OtbnComponent {
OtbnComponent { mux_otbn }
}
}
impl Component for OtbnComponent {
type StaticInput = &'static mut MaybeUninit<VirtualMuxAccel<'static>>;
type Output = &'static VirtualMuxAccel<'static>;
fn finalize(self, s: Self::StaticInput) -> Self::Output {
let virtual_otbn_user = s.write(VirtualMuxAccel::new(self.mux_otbn));
virtual_otbn_user
}
}
/// Find the OTBN app in the Tock process list
///
/// This will iterate through the app list inside the `app_flash` looking
/// for a disabled app with the same name as `name`.
/// On success this function will return the following information:
/// * OTBN imem start address
/// * OTBN imem size
/// * OTBN dmem start address
/// * OTBN dmem size
///
/// This function is based on the Tock process loading code
#[allow(dead_code)]
pub fn find_app(name: &str, app_flash: &'static [u8]) -> Result<(usize, usize, usize, usize), ()> {
let mut remaining_flash = app_flash;
loop {
// Get the first eight bytes of flash to check if there is another
// app.
let test_header_slice = match remaining_flash.get(0..8) {
Some(s) => s,
None => {
// Not enough flash to test for another app. This just means
// we are at the end of flash, and there are no more apps to
// load.
return Err(());
}
};
// Pass the first eight bytes to tbfheader to parse out the length of
// the tbf header and app. We then use those values to see if we have
// enough flash remaining to parse the remainder of the header.
let (version, header_length, entry_length) = match tock_tbf::parse::parse_tbf_header_lengths(
test_header_slice.try_into().or(Err(()))?,
) {
Ok((v, hl, el)) => (v, hl, el),
Err(tock_tbf::types::InitialTbfParseError::InvalidHeader(entry_length)) => {
// If we could not parse the header, then we want to skip over
// this app and look for the next one.
(0, 0, entry_length)
}
Err(tock_tbf::types::InitialTbfParseError::UnableToParse) => {
// Since Tock apps use a linked list, it is very possible the
// header we started to parse is intentionally invalid to signal
// the end of apps. This is ok and just means we have finished
// loading apps.
return Err(());
}
};
// Now we can get a slice which only encompasses the length of flash
// described by this tbf header. We will either parse this as an actual
// app, or skip over this region.
let entry_flash = remaining_flash.get(0..entry_length as usize).ok_or(())?;
// Advance the flash slice for process discovery beyond this last entry.
// This will be the start of where we look for a new process since Tock
// processes are allocated back-to-back in flash.
remaining_flash = remaining_flash.get(entry_flash.len()..).ok_or(())?;
if header_length > 0 {
// If we found an actual app header, try to create a `Process`
// object. We also need to shrink the amount of remaining memory
// based on whatever is assigned to the new process if one is
// created.
// Get a slice for just the app header.
let header_flash = entry_flash.get(0..header_length as usize).ok_or(())?;
// Parse the full TBF header to see if this is a valid app. If the
// header can't parse, we will error right here.
if let Ok(tbf_header) = tock_tbf::parse::parse_tbf_header(header_flash, version) {
let process_name = tbf_header.get_package_name().unwrap();
// If the app is enabled, it's a real app and not what we are looking for.
if tbf_header.enabled() {
continue;
}
if name != process_name {
continue;
}
let dmem_length = tbf_header.get_minimum_app_ram_size();
let imem_start =
unsafe { entry_flash.as_ptr().offset(header_length as isize) as usize };
let imem_length = entry_length - dmem_length - header_length as u32 - 4;
let dmem_start = unsafe {
entry_flash
.as_ptr()
.offset(header_length as isize + imem_length as isize)
as usize
};
return Ok((
imem_start,
imem_length as usize,
dmem_start,
dmem_length as usize,
));
}
};
}
}