From aebc739c1e6b8afd3a6adcb9bc35b2b062a9c3cd Mon Sep 17 00:00:00 2001 From: mwojcik Date: Tue, 31 Oct 2023 17:24:55 +0800 Subject: [PATCH] add support for tar flashable (sub)kernels --- flake.nix | 3 ++ src/Cargo.lock | 17 ++++++++ src/runtime/Cargo.toml.tpl | 6 ++- src/runtime/src/comms.rs | 87 +++++++++++++++++++++++++++++++++++--- 4 files changed, 107 insertions(+), 6 deletions(-) diff --git a/flake.nix b/flake.nix index df4f03a1..9c858ce7 100644 --- a/flake.nix +++ b/flake.nix @@ -122,6 +122,9 @@ src = ./src; cargoLock = { lockFile = src/Cargo.lock; + outputHashes = { + "tar-no-std-0.1.8" = "sha256-xm17108v4smXOqxdLvHl9CxTCJslmeogjm4Y87IXFuM="; + }; }; nativeBuildInputs = [ diff --git a/src/Cargo.lock b/src/Cargo.lock index 01162ee5..de037264 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "async-recursion" version = "0.3.2" @@ -474,6 +480,7 @@ dependencies = [ "log_buffer", "num-derive", "num-traits", + "tar-no-std", "unwind", "vcell", "void", @@ -538,6 +545,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tar-no-std" +version = "0.1.8" +source = "git+https://git.m-labs.hk/M-Labs/tar-no-std?rev=2ab6dc5#2ab6dc58e5249c59c4eb03eaf3a119bcdd678d32" +dependencies = [ + "arrayvec", + "bitflags", + "log", +] + [[package]] name = "unicode-ident" version = "1.0.5" diff --git a/src/runtime/Cargo.toml.tpl b/src/runtime/Cargo.toml.tpl index a0c7fa76..9f539e04 100644 --- a/src/runtime/Cargo.toml.tpl +++ b/src/runtime/Cargo.toml.tpl @@ -40,4 +40,8 @@ unwind = { path = "../libunwind" } libc = { path = "../libc" } io = { path = "../libio", features = ["alloc"] } ksupport = { path = "../libksupport" } -libboard_artiq = { path = "../libboard_artiq" } \ No newline at end of file +libboard_artiq = { path = "../libboard_artiq" } + +[dependencies.tar-no-std] +git = "https://git.m-labs.hk/M-Labs/tar-no-std" +rev = "2ab6dc5" \ No newline at end of file diff --git a/src/runtime/src/comms.rs b/src/runtime/src/comms.rs index 26a09e69..ed646488 100644 --- a/src/runtime/src/comms.rs +++ b/src/runtime/src/comms.rs @@ -3,17 +3,23 @@ use core::{cell::RefCell, fmt, slice, str}; use core_io::Error as IoError; use cslice::CSlice; +#[cfg(has_drtio)] +use dyld::elf; use futures::{future::FutureExt, select_biased}; #[cfg(has_drtio)] use io::Cursor; #[cfg(has_drtio)] use ksupport::rpc; use ksupport::{kernel, resolve_channel_name}; +#[cfg(has_drtio)] +use libasync::delay; use libasync::{smoltcp::{Sockets, TcpStream}, task}; use libboard_artiq::drtio_routing; #[cfg(feature = "target_kasli_soc")] use libboard_zynq::error_led::ErrorLED; +#[cfg(has_drtio)] +use libboard_zynq::time::Milliseconds; use libboard_zynq::{self as zynq, smoltcp::{self, iface::{EthernetInterfaceBuilder, NeighborCache}, @@ -27,6 +33,8 @@ use libcortex_a9::{mutex::Mutex, use log::{error, info, warn}; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive, ToPrimitive}; +#[cfg(has_drtio)] +use tar_no_std::TarArchiveRef; #[cfg(has_drtio)] use crate::pl; @@ -43,6 +51,8 @@ pub enum Error { BufferExhausted, #[cfg(has_drtio)] SubkernelError(subkernel::Error), + #[cfg(has_drtio)] + DestinationDown, } pub type Result = core::result::Result; @@ -57,6 +67,8 @@ impl fmt::Display for Error { Error::BufferExhausted => write!(f, "buffer exhausted"), #[cfg(has_drtio)] Error::SubkernelError(error) => write!(f, "subkernel error: {:?}", error), + #[cfg(has_drtio)] + Error::DestinationDown => write!(f, "subkernel destination down"), } } } @@ -538,6 +550,56 @@ async fn handle_run_kernel( Ok(()) } +async fn handle_flash_kernel( + buffer: &Vec, + control: &Rc>, + _up_destinations: &Rc>, + _aux_mutex: &Rc>, + _routing_table: &drtio_routing::RoutingTable, + _timer: GlobalTimer, +) -> Result<()> { + if buffer[0] == elf::ELFMAG0 && buffer[1] == elf::ELFMAG1 && buffer[2] == elf::ELFMAG2 && buffer[3] == elf::ELFMAG3 + { + // assume ELF file, proceed as before + load_kernel(buffer, control, None).await + } else { + #[cfg(has_drtio)] + { + let archive = TarArchiveRef::new(buffer.as_ref()); + let entries = archive.entries(); + let mut main_lib: Vec = Vec::new(); + for entry in entries { + if entry.filename().as_str() == "main.elf" { + main_lib = entry.data().to_vec(); + } else { + // subkernel filename must be in format: + // " .elf" + let filename = entry.filename(); + let mut iter = filename.as_str().split_whitespace(); + let sid: u32 = iter.next().unwrap().parse().unwrap(); + let dest: u8 = iter.next().unwrap().strip_suffix(".elf").unwrap().parse().unwrap(); + let up = _up_destinations.borrow()[dest as usize]; + if up { + let subkernel_lib = entry.data().to_vec(); + subkernel::add_subkernel(sid, dest, subkernel_lib).await; + match subkernel::upload(_aux_mutex, _routing_table, _timer, sid).await { + Ok(_) => (), + Err(_) => return Err(Error::UnexpectedPattern), + } + } else { + return Err(Error::DestinationDown); + } + } + } + load_kernel(&main_lib, control, None).await + } + #[cfg(not(has_drtio))] + { + panic!("multi-kernel libraries are not supported in standalone systems"); + } + } +} + async fn load_kernel( buffer: &Vec, control: &Rc>, @@ -693,7 +755,6 @@ pub fn main(timer: GlobalTimer, cfg: Config) { Sockets::init(32); - // before, mutex was on io, but now that io isn't used...? let aux_mutex: Rc> = Rc::new(Mutex::new(false)); #[cfg(has_drtio)] let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::config_routing_table( @@ -716,9 +777,16 @@ pub fn main(timer: GlobalTimer, cfg: Config) { let idle_kernel = Rc::new(cfg.read("idle_kernel").ok()); if let Ok(buffer) = cfg.read("startup_kernel") { info!("Loading startup kernel..."); - if let Ok(()) = task::block_on(load_kernel(&buffer, &control, None)) { + let routing_table = drtio_routing_table.borrow(); + if let Ok(()) = task::block_on(handle_flash_kernel( + &buffer, + &control, + &up_destinations, + &aux_mutex, + &routing_table, + timer, + )) { info!("Starting startup kernel..."); - let routing_table = drtio_routing_table.borrow(); let _ = task::block_on(handle_run_kernel( None, &control, @@ -766,8 +834,17 @@ pub fn main(timer: GlobalTimer, cfg: Config) { .map_err(|e| warn!("connection terminated: {}", e)); if let Some(buffer) = &*idle_kernel { info!("Loading idle kernel"); - let _ = load_kernel(&buffer, &control, None) - .await.map_err(|_| warn!("error loading idle kernel")); + let res = handle_flash_kernel(&buffer, &control, &up_destinations, &aux_mutex, &routing_table, timer) + .await; + match res { + #[cfg(has_drtio)] + Err(Error::DestinationDown) => { + let mut countdown = timer.countdown(); + delay(&mut countdown, Milliseconds(500)).await; + } + Err(_) => warn!("error loading idle kernel"), + _ => (), + } info!("Running idle kernel"); let _ = handle_run_kernel(None, &control, &up_destinations, &aux_mutex, &routing_table, timer) .await.map_err(|_| warn!("error running idle kernel"));