mgmt: implement flash via drtio

This commit is contained in:
occheung 2024-09-02 16:57:38 +08:00
parent 64c69f46c9
commit c17e0e2b71
6 changed files with 137 additions and 33 deletions

View File

@ -554,6 +554,8 @@ dependencies = [
"board_artiq",
"board_misoc",
"build_misoc",
"byteorder",
"crc",
"cslice",
"eh",
"io",

View File

@ -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 },
@ -503,6 +504,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))
})
@ -873,6 +887,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(())
}

View File

@ -521,8 +521,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<u8>) -> Result<(), Error<SchedError>> {
todo!()
destination: u8, stream: &mut TcpStream, image: &[u8]) -> Result<(), Error<SchedError>> {
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())
},
}
}
}
@ -566,7 +591,7 @@ fn worker(io: &Io, _aux_mutex: &Mutex, _ddma_mutex: &Mutex, _subkernel_mutex: &M
Request::ConfigErase => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_erase),
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[..]),
}?;
}
}

View File

@ -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"] }

View File

@ -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;
@ -552,10 +554,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 {
@ -579,6 +581,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");

View File

@ -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<Vec<u8>>,
config_payload: Cursor<Vec<u8>>,
image_payload: Cursor<Vec<u8>>,
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 })
}
}
}