From bb8148e554ba6744a60d8e06e624f37dc6d3f861 Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 2 Sep 2024 16:57:38 +0800 Subject: [PATCH] mgmt: implement flash via drtio --- artiq/firmware/Cargo.lock | 2 + .../firmware/libproto_artiq/drtioaux_proto.rs | 21 ++++ artiq/firmware/runtime/mgmt.rs | 31 +++++- artiq/firmware/satman/Cargo.toml | 2 + artiq/firmware/satman/main.rs | 16 ++- artiq/firmware/satman/mgmt.rs | 98 +++++++++++++------ 6 files changed, 137 insertions(+), 33 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index a14353341..aa156989e 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -554,6 +554,8 @@ dependencies = [ "board_artiq", "board_misoc", "build_misoc", + "byteorder", + "crc", "cslice", "eh", "io", diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 4aeeaec12..267b983df 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -139,6 +139,7 @@ pub enum Packet { CoreMgmtConfigEraseRequest { destination: u8 }, CoreMgmtRebootRequest { destination: u8 }, CoreMgmtAllocatorDebugRequest { destination: u8 }, + CoreMgmtFlashRequest { destination: u8, last: bool, length: u16, data: [u8; MASTER_PAYLOAD_MAX_SIZE] }, CoreMgmtGetLogReply { last: bool, length: u16, data: [u8; SAT_PAYLOAD_MAX_SIZE] }, CoreMgmtConfigReadReply { last: bool, length: u16, value: [u8; SAT_PAYLOAD_MAX_SIZE] }, CoreMgmtReply { succeeded: bool }, @@ -507,6 +508,19 @@ impl Packet { 0xdd => Packet::CoreMgmtReply { succeeded: reader.read_bool()?, }, + 0xde => { + let destination = reader.read_u8()?; + let last = reader.read_bool()?; + let length = reader.read_u16()?; + let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE]; + reader.read_exact(&mut data[0..length as usize])?; + Packet::CoreMgmtFlashRequest { + destination: destination, + last: last, + length: length, + data: data, + } + }, ty => return Err(Error::UnknownPacket(ty)) }) @@ -880,6 +894,13 @@ impl Packet { writer.write_u8(0xdd)?; writer.write_bool(succeeded)?; }, + Packet::CoreMgmtFlashRequest { destination, last, length, data } => { + writer.write_u8(0xde)?; + writer.write_u8(destination)?; + writer.write_bool(last)?; + writer.write_u16(length)?; + writer.write_all(&data[..length as usize])?; + }, } Ok(()) } diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 33959f9cd..65567b3bc 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -542,8 +542,33 @@ mod remote_coremgmt { pub fn flash(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, linkno: u8, - destination: u8, stream: &mut TcpStream, image: &Vec) -> Result<(), Error> { - todo!() + destination: u8, stream: &mut TcpStream, image: &[u8]) -> Result<(), Error> { + + match drtio::partition_data(&image, |slice, status, len: usize| { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, + &Packet::CoreMgmtFlashRequest { + destination: destination, length: len as u16, last: status.is_last(), data: *slice}); + match reply { + Ok(Packet::CoreMgmtReply { succeeded: true }) => Ok(()), + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); + Err(drtio::Error::UnexpectedReply) + } + Err(e) => { + error!("aux packet error ({})", e); + Err(e) + } + } + }) { + Ok(()) => { + Reply::RebootImminent.write_to(stream)?; + Ok(()) + }, + Err(e) => { + Reply::Error.write_to(stream)?; + Err(e.into()) + }, + } } } @@ -588,7 +613,7 @@ fn worker(io: &Io, stream: &mut TcpStream, restart_idle: &Urc>, Request::ConfigErase => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_erase, restart_idle), Request::Reboot => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, reboot), Request::DebugAllocator => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, debug_allocator), - Request::Flash { ref image } => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, flash, image), + Request::Flash { ref image } => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, flash, &image[..]), }?; } } diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index f8016f576..522ae7b32 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -15,6 +15,8 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] log = { version = "0.4", default-features = false } io = { path = "../libio", features = ["byteorder", "alloc"] } +byteorder = { version = "1.0", default-features = false } +crc = { version = "1.7", default-features = false } cslice = { version = "0.3" } board_misoc = { path = "../libboard_misoc", features = ["uart_console", "log"] } board_artiq = { path = "../libboard_artiq", features = ["alloc"] } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 16ccf31fb..9a98528a6 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -9,6 +9,8 @@ extern crate board_artiq; extern crate riscv; extern crate alloc; extern crate proto_artiq; +extern crate byteorder; +extern crate crc; extern crate cslice; extern crate io; extern crate eh; @@ -558,10 +560,10 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg }, ) } - drtioaux::Packet::CoreMgmtConfigWriteRequest { destination: _destination, length, last, data } => { + drtioaux::Packet::CoreMgmtConfigWriteRequest { destination: _destination, last, length, data } => { forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); - coremgr.add_data(&data, length as usize); + coremgr.add_config_data(&data, length as usize); if last { coremgr.write_config() } else { @@ -585,6 +587,16 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg warn!("restarting"); unsafe { spiflash::reload(); } } + drtioaux::Packet::CoreMgmtFlashRequest { destination: _destination, last, length, data } => { + forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); + + coremgr.add_image_data(&data, length as usize); + if last { + coremgr.flash_image() + } else { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true }) + } + } _ => { warn!("received unexpected aux packet"); diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs index 86e5794e3..911a15d5d 100644 --- a/artiq/firmware/satman/mgmt.rs +++ b/artiq/firmware/satman/mgmt.rs @@ -1,21 +1,25 @@ use alloc::vec::Vec; +use byteorder::{ByteOrder, NativeEndian}; +use crc::crc32; use routing::{Sliceable, SliceMeta}; use board_artiq::drtioaux; -use board_misoc::{clock, config, csr, spiflash}; +use board_misoc::{mem, clock, config, csr, spiflash}; use io::{Cursor, ProtoRead, ProtoWrite}; use proto_artiq::drtioaux_proto::SAT_PAYLOAD_MAX_SIZE; pub struct Manager { - current_payload: Cursor>, + config_payload: Cursor>, + image_payload: Cursor>, last_value: Sliceable, } impl Manager { pub fn new() -> Manager { Manager { - current_payload: Cursor::new(Vec::new()), + config_payload: Cursor::new(Vec::new()), + image_payload: Cursor::new(Vec::new()), last_value: Sliceable::new(0, Vec::new()), } } @@ -30,49 +34,87 @@ impl Manager { self.last_value.get_slice_sat(data_slice) } - pub fn add_data(&mut self, data: &[u8], data_len: usize) { - self.current_payload.write_all(&data[..data_len]).unwrap(); + pub fn add_config_data(&mut self, data: &[u8], data_len: usize) { + self.config_payload.write_all(&data[..data_len]).unwrap(); } - pub fn clear_data(&mut self) { - self.current_payload.get_mut().clear(); - self.current_payload.set_position(0); + pub fn clear_config_data(&mut self) { + self.config_payload.get_mut().clear(); + self.config_payload.set_position(0); } pub fn write_config(&mut self) -> Result<(), drtioaux::Error> { - let key = match self.current_payload.read_string() { + let key = match self.config_payload.read_string() { Ok(key) => key, Err(err) => { - self.clear_data(); + self.clear_config_data(); error!("error on reading key: {:?}", err); return drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }); } }; - let value = self.current_payload.read_bytes().unwrap(); + let value = self.config_payload.read_bytes().unwrap(); - match key.as_str() { - "gateware" | "bootloader" | "firmware" => { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })?; - #[cfg(not(soc_platform = "efc"))] - unsafe { - clock::spin_us(10000); - csr::gt_drtio::txenable_write(0); - } - config::write(&key, &value).expect("failed to write to flash storage"); - warn!("restarting"); - unsafe { spiflash::reload(); } + let succeeded = config::write(&key, &value).map_err(|err| { + error!("error on writing config: {:?}", err); + }).is_ok(); + + self.clear_config_data(); + + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded }) + } + + pub fn add_image_data(&mut self, data: &[u8], data_len: usize) { + self.image_payload.write_all(&data[..data_len]).unwrap(); + } + + pub fn clear_image_data(&mut self) { + self.image_payload.get_mut().clear(); + self.image_payload.set_position(0); + } + + pub fn flash_image(&mut self) -> Result<(), drtioaux::Error> { + let image = &self.image_payload.get_ref()[..]; + + let (expected_crc, mut image) = { + let (image, crc_slice) = image.split_at(image.len() - 4); + (NativeEndian::read_u32(crc_slice), image) + }; + + let actual_crc = crc32::checksum_ieee(image); + + if actual_crc == expected_crc { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })?; + #[cfg(not(soc_platform = "efc"))] + unsafe { + clock::spin_us(10000); + csr::gt_drtio::txenable_write(0); } - _ => { - let succeeded = config::write(&key, &value).map_err(|err| { - error!("error on writing config: {:?}", err); - }).is_ok(); + let bin_origins = [ + ("gateware" , 0 ), + ("bootloader", mem::ROM_BASE ), + ("firmware" , mem::FLASH_BOOT_ADDRESS), + ]; - self.clear_data(); + for (name, origin) in bin_origins { + info!("Flashing {} binary...", name); + let size = NativeEndian::read_u32(&image[..4]) as usize; + image = &image[4..]; - drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded }) + let (bin, remaining) = image.split_at(size); + image = remaining; + + unsafe { spiflash::flash_binary(origin, bin) }; } + + warn!("restarting"); + unsafe { spiflash::reload(); } + + } else { + error!("CRC failed in SDRAM (actual {:08x}, expected {:08x})", actual_crc, expected_crc); + self.clear_image_data(); + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }) } } }