Compare commits

...

25 Commits

Author SHA1 Message Date
occheung 3ebbb554cd cargo fmt 2024-10-24 12:58:57 +08:00
occheung e6df69fe04 drtio_proto: add allocate step for flashing
This avoids reallocation while transfering binaries.
2024-10-24 12:32:01 +08:00
occheung b561099ec3 satman: fix checksum error message 2024-10-24 11:52:26 +08:00
occheung 5c2efa7989 runtime: check crc when flashing 2024-10-24 11:52:04 +08:00
occheung 1892320b06 cargo fmt 2024-09-20 17:10:08 +08:00
occheung 6840a39b1d mgmt: supplementary tuple -> tuple struct 2024-09-20 17:09:29 +08:00
occheung a921755e39 cargo fmt 2024-09-20 17:08:53 +08:00
occheung 93e25169fb runtime mgmt: avoid pull_log resource hog 2024-09-19 17:16:47 +08:00
occheung ed813013b0 runtime mgmt: avoid passing incomplete log to core_log 2024-09-19 17:16:18 +08:00
occheung e6ba1fbf1a satman mgmt: fix uart log level change message 2024-09-19 17:15:31 +08:00
occheung 83da524ad2 satman mgmt: allow sliceable to consume log source 2024-09-19 17:15:01 +08:00
occheung 349e537626 satman mgmt: get logger unconditionally 2024-09-19 17:14:18 +08:00
occheung da4b59fb42 mgmt: minor fix 2024-09-19 17:13:44 +08:00
occheung acd5e2c12c drtio-proto: avoid expecting response to drop link ack 2024-09-19 12:48:11 +08:00
occheung 7b6cbadb08 coremgmt: fix import/uses 2024-09-19 12:48:10 +08:00
occheung b285a21fc5 coremgmt: remove unnecsaary cursors 2024-09-19 12:47:23 +08:00
occheung dd7c8c8c3d runtime coremgmt: implement firmware rewrite 2024-09-19 12:47:23 +08:00
occheung 3cf2d6be9d satman coremgmt: code after reboot is unreachable 2024-09-19 12:47:23 +08:00
occheung 1fc059f47a cargo fmt 2024-09-19 12:47:22 +08:00
occheung deb223975c satman: implement boot file rewrite sequence 2024-09-19 12:45:59 +08:00
occheung e7fbedd8ec coremgr: current_payload -> config_payload 2024-09-19 12:45:59 +08:00
occheung 13e4b2c40c drtio-proto: (N)ACK -> Reply { succeeded } 2024-09-19 12:45:59 +08:00
occheung 2bc4ff2c9b drtio-proto: add coremgmt-over-drtio messages 2024-09-19 12:45:59 +08:00
occheung 33e8d6882a runtime: support coremgmt on satellites 2024-09-19 12:45:58 +08:00
occheung 0c3474f5b5 satman: implement cfg/mgmt operations 2024-09-19 12:34:24 +08:00
10 changed files with 1645 additions and 97 deletions

2
src/Cargo.lock generated
View File

@ -559,7 +559,9 @@ name = "satman"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"build_zynq", "build_zynq",
"byteorder",
"core_io", "core_io",
"crc",
"cslice", "cslice",
"embedded-hal", "embedded-hal",
"io", "io",

View File

@ -287,6 +287,77 @@ pub enum Packet {
SubkernelMessageAck { SubkernelMessageAck {
destination: u8, destination: u8,
}, },
CoreMgmtGetLogRequest {
destination: u8,
clear: bool,
},
CoreMgmtClearLogRequest {
destination: u8,
},
CoreMgmtSetLogLevelRequest {
destination: u8,
log_level: u8,
},
CoreMgmtSetUartLogLevelRequest {
destination: u8,
log_level: u8,
},
CoreMgmtConfigReadRequest {
destination: u8,
length: u16,
key: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
CoreMgmtConfigReadContinue {
destination: u8,
},
CoreMgmtConfigWriteRequest {
destination: u8,
last: bool,
length: u16,
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
CoreMgmtConfigRemoveRequest {
destination: u8,
length: u16,
key: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
CoreMgmtConfigEraseRequest {
destination: u8,
},
CoreMgmtRebootRequest {
destination: u8,
},
CoreMgmtAllocatorDebugRequest {
destination: u8,
},
CoreMgmtFlashRequest {
destination: u8,
payload_length: u32,
},
CoreMgmtFlashAddDataRequest {
destination: u8,
last: bool,
length: u16,
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
CoreMgmtDropLinkAck {
destination: u8,
},
CoreMgmtDropLink,
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,
},
} }
impl Packet { impl Packet {
@ -563,6 +634,115 @@ impl Packet {
destination: reader.read_u8()?, destination: reader.read_u8()?,
}, },
0xd0 => Packet::CoreMgmtGetLogRequest {
destination: reader.read_u8()?,
clear: reader.read_bool()?,
},
0xd1 => Packet::CoreMgmtClearLogRequest {
destination: reader.read_u8()?,
},
0xd2 => Packet::CoreMgmtSetLogLevelRequest {
destination: reader.read_u8()?,
log_level: reader.read_u8()?,
},
0xd3 => Packet::CoreMgmtSetUartLogLevelRequest {
destination: reader.read_u8()?,
log_level: reader.read_u8()?,
},
0xd4 => {
let destination = reader.read_u8()?;
let length = reader.read_u16()?;
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut key[0..length as usize])?;
Packet::CoreMgmtConfigReadRequest {
destination: destination,
length: length,
key: key,
}
}
0xd5 => Packet::CoreMgmtConfigReadContinue {
destination: reader.read_u8()?,
},
0xd6 => {
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::CoreMgmtConfigWriteRequest {
destination: destination,
last: last,
length: length,
data: data,
}
}
0xd7 => {
let destination = reader.read_u8()?;
let length = reader.read_u16()?;
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut key[0..length as usize])?;
Packet::CoreMgmtConfigRemoveRequest {
destination: destination,
length: length,
key: key,
}
}
0xd8 => Packet::CoreMgmtConfigEraseRequest {
destination: reader.read_u8()?,
},
0xd9 => Packet::CoreMgmtRebootRequest {
destination: reader.read_u8()?,
},
0xda => Packet::CoreMgmtAllocatorDebugRequest {
destination: reader.read_u8()?,
},
0xdb => Packet::CoreMgmtFlashRequest {
destination: reader.read_u8()?,
payload_length: reader.read_u32()?,
},
0xdc => {
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::CoreMgmtFlashAddDataRequest {
destination: destination,
last: last,
length: length,
data: data,
}
}
0xdd => Packet::CoreMgmtDropLinkAck {
destination: reader.read_u8()?,
},
0xde => Packet::CoreMgmtDropLink,
0xdf => {
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::CoreMgmtGetLogReply {
last: last,
length: length,
data: data,
}
}
0xe0 => {
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut value: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut value[0..length as usize])?;
Packet::CoreMgmtConfigReadReply {
last: last,
length: length,
value: value,
}
}
0xe1 => Packet::CoreMgmtReply {
succeeded: reader.read_bool()?,
},
ty => return Err(Error::UnknownPacket(ty)), ty => return Err(Error::UnknownPacket(ty)),
}) })
} }
@ -938,6 +1118,115 @@ impl Packet {
writer.write_u8(0xcc)?; writer.write_u8(0xcc)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
} }
Packet::CoreMgmtGetLogRequest { destination, clear } => {
writer.write_u8(0xd0)?;
writer.write_u8(destination)?;
writer.write_bool(clear)?;
}
Packet::CoreMgmtClearLogRequest { destination } => {
writer.write_u8(0xd1)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtSetLogLevelRequest { destination, log_level } => {
writer.write_u8(0xd2)?;
writer.write_u8(destination)?;
writer.write_u8(log_level)?;
}
Packet::CoreMgmtSetUartLogLevelRequest { destination, log_level } => {
writer.write_u8(0xd3)?;
writer.write_u8(destination)?;
writer.write_u8(log_level)?;
}
Packet::CoreMgmtConfigReadRequest {
destination,
length,
key,
} => {
writer.write_u8(0xd4)?;
writer.write_u8(destination)?;
writer.write_u16(length)?;
writer.write_all(&key[0..length as usize])?;
}
Packet::CoreMgmtConfigReadContinue { destination } => {
writer.write_u8(0xd5)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtConfigWriteRequest {
destination,
last,
length,
data,
} => {
writer.write_u8(0xd6)?;
writer.write_u8(destination)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&data[0..length as usize])?;
}
Packet::CoreMgmtConfigRemoveRequest {
destination,
length,
key,
} => {
writer.write_u8(0xd7)?;
writer.write_u8(destination)?;
writer.write_u16(length)?;
writer.write_all(&key[0..length as usize])?;
}
Packet::CoreMgmtConfigEraseRequest { destination } => {
writer.write_u8(0xd8)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtRebootRequest { destination } => {
writer.write_u8(0xd9)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtAllocatorDebugRequest { destination } => {
writer.write_u8(0xda)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtFlashRequest {
destination,
payload_length,
} => {
writer.write_u8(0xdb)?;
writer.write_u8(destination)?;
writer.write_u32(payload_length)?;
}
Packet::CoreMgmtFlashAddDataRequest {
destination,
last,
length,
data,
} => {
writer.write_u8(0xdc)?;
writer.write_u8(destination)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&data[..length as usize])?;
}
Packet::CoreMgmtDropLinkAck { destination } => {
writer.write_u8(0xdd)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtDropLink => writer.write_u8(0xde)?,
Packet::CoreMgmtGetLogReply { last, length, data } => {
writer.write_u8(0xdf)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&data[0..length as usize])?;
}
Packet::CoreMgmtConfigReadReply { last, length, value } => {
writer.write_u8(0xe0)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&value[0..length as usize])?;
}
Packet::CoreMgmtReply { succeeded } => {
writer.write_u8(0xe1)?;
writer.write_bool(succeeded)?;
}
} }
Ok(()) Ok(())
} }
@ -974,7 +1263,8 @@ impl Packet {
| Packet::SubkernelLoadRunReply { .. } | Packet::SubkernelLoadRunReply { .. }
| Packet::SubkernelMessageAck { .. } | Packet::SubkernelMessageAck { .. }
| Packet::DmaPlaybackStatus { .. } | Packet::DmaPlaybackStatus { .. }
| Packet::SubkernelFinished { .. } => false, | Packet::SubkernelFinished { .. }
| Packet::CoreMgmtDropLinkAck { .. } => false,
_ => true, _ => true,
} }
} }

View File

@ -20,6 +20,7 @@ cslice = "0.3"
log = "0.4" log = "0.4"
embedded-hal = "0.2" embedded-hal = "0.2"
core_io = { version = "0.1", features = ["collections"] } core_io = { version = "0.1", features = ["collections"] }
crc = { version = "1.7", default-features = false }
byteorder = { version = "1.3", default-features = false } byteorder = { version = "1.3", default-features = false }
void = { version = "1", default-features = false } void = { version = "1", default-features = false }
futures = { version = "0.3", default-features = false, features = ["async-await"] } futures = { version = "0.3", default-features = false, features = ["async-await"] }

View File

@ -784,7 +784,11 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
let cfg = Rc::new(cfg); let cfg = Rc::new(cfg);
let restart_idle = Rc::new(Semaphore::new(1, 1)); let restart_idle = Rc::new(Semaphore::new(1, 1));
mgmt::start(cfg.clone(), restart_idle.clone()); mgmt::start(
cfg.clone(),
restart_idle.clone(),
Some(mgmt::DrtioTuple(aux_mutex.clone(), drtio_routing_table.clone(), timer)),
);
task::spawn(async move { task::spawn(async move {
let connection = Rc::new(Semaphore::new(1, 1)); let connection = Rc::new(Semaphore::new(1, 1));
@ -910,7 +914,7 @@ pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
Sockets::init(32); Sockets::init(32);
let dummy = Rc::new(Semaphore::new(0, 1)); let dummy = Rc::new(Semaphore::new(0, 1));
mgmt::start(Rc::new(cfg), dummy); mgmt::start(Rc::new(cfg), dummy, None);
// getting eth settings disables the LED as it resets GPIO // getting eth settings disables the LED as it resets GPIO
// need to re-enable it here // need to re-enable it here

View File

@ -1,17 +1,22 @@
use alloc::{rc::Rc, string::String, vec::Vec}; use alloc::{rc::Rc, string::String, vec::Vec};
use core::cell::RefCell; use core::cell::RefCell;
use byteorder::{ByteOrder, NativeEndian};
use crc::crc32;
use futures::{future::poll_fn, task::Poll}; use futures::{future::poll_fn, task::Poll};
use libasync::{smoltcp::TcpStream, task}; use libasync::{smoltcp::TcpStream, task};
use libboard_artiq::logger::{BufferLogger, LogBufferRef}; use libboard_artiq::{drtio_routing::RoutingTable,
use libboard_zynq::{slcr, smoltcp}; logger::{BufferLogger, LogBufferRef}};
use libboard_zynq::{smoltcp, timer::GlobalTimer};
use libconfig::Config; use libconfig::Config;
use libcortex_a9::semaphore::Semaphore; use libcortex_a9::{mutex::Mutex, semaphore::Semaphore};
use log::{self, debug, error, info, warn, LevelFilter}; use log::{self, debug, error, info, warn};
use num_derive::FromPrimitive; use num_derive::FromPrimitive;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use crate::proto_async::*; use crate::proto_async::*;
#[cfg(has_drtio)]
use crate::rtio_mgt::drtio;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error { pub enum Error {
@ -19,6 +24,8 @@ pub enum Error {
UnknownLogLevel(u8), UnknownLogLevel(u8),
UnexpectedPattern, UnexpectedPattern,
UnrecognizedPacket, UnrecognizedPacket,
#[cfg(has_drtio)]
DrtioError(drtio::Error),
} }
type Result<T> = core::result::Result<T, Error>; type Result<T> = core::result::Result<T, Error>;
@ -30,6 +37,8 @@ impl core::fmt::Display for Error {
&Error::UnknownLogLevel(lvl) => write!(f, "unknown log level {}", lvl), &Error::UnknownLogLevel(lvl) => write!(f, "unknown log level {}", lvl),
&Error::UnexpectedPattern => write!(f, "unexpected pattern"), &Error::UnexpectedPattern => write!(f, "unexpected pattern"),
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"), &Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
#[cfg(has_drtio)]
&Error::DrtioError(error) => write!(f, "drtio error: {}", error),
} }
} }
} }
@ -40,6 +49,13 @@ impl From<smoltcp::Error> for Error {
} }
} }
#[cfg(has_drtio)]
impl From<drtio::Error> for Error {
fn from(error: drtio::Error) -> Self {
Error::DrtioError(error)
}
}
#[derive(Debug, FromPrimitive)] #[derive(Debug, FromPrimitive)]
pub enum Request { pub enum Request {
GetLog = 1, GetLog = 1,
@ -52,6 +68,11 @@ pub enum Request {
ConfigRead = 12, ConfigRead = 12,
ConfigWrite = 13, ConfigWrite = 13,
ConfigRemove = 14, ConfigRemove = 14,
ConfigErase = 15,
DebugAllocator = 8,
Flash = 9,
} }
#[repr(i8)] #[repr(i8)]
@ -112,35 +133,606 @@ async fn read_key(stream: &mut TcpStream) -> Result<String> {
Ok(String::from_utf8(buffer).unwrap()) Ok(String::from_utf8(buffer).unwrap())
} }
async fn handle_connection( #[cfg(has_drtio)]
stream: &mut TcpStream, mod remote_coremgmt {
pull_id: Rc<RefCell<u32>>, use core_io::Read;
cfg: Rc<Config>, use io::ProtoWrite;
restart_idle: Rc<Semaphore>, use libboard_artiq::{drtioaux_async,
) -> Result<()> { drtioaux_proto::{Packet, MASTER_PAYLOAD_MAX_SIZE}};
if !expect(&stream, b"ARTIQ management\n").await? {
return Err(Error::UnexpectedPattern);
}
stream.send_slice("e".as_bytes()).await?;
use super::*;
pub async fn get_log(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
) -> Result<()> {
let mut buffer = Vec::new();
loop { loop {
let msg = read_i8(stream).await; let reply = drtio::aux_transact(
if let Err(smoltcp::Error::Finished) = msg { aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtGetLogRequest {
destination,
clear: false,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtGetLogReply { last, length, data }) => {
buffer.extend(&data[..length as usize]);
if last {
write_i8(stream, Reply::LogContent as i8).await?;
write_chunk(stream, &buffer).await?;
return Ok(()); return Ok(());
} }
let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?; }
match msg { Ok(packet) => {
Request::GetLog => { error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
return Err(drtio::Error::UnexpectedReply.into());
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
return Err(e.into());
}
}
}
}
pub async fn clear_log(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
) -> Result<()> {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtClearLogRequest { destination },
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn pull_log(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
pull_id: &Rc<RefCell<u32>>,
) -> Result<()> {
let id = {
let mut guard = pull_id.borrow_mut();
*guard += 1;
*guard
};
let mut buffer = Vec::new();
loop {
if id != *pull_id.borrow() {
// another connection attempts to pull the log...
// abort this connection...
break;
}
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtGetLogRequest {
destination,
clear: true,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtGetLogReply { last, length, data }) => {
buffer.extend(&data[..length as usize]);
if last {
write_chunk(stream, &buffer).await?;
buffer.clear();
task::r#yield().await;
}
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
return Err(drtio::Error::UnexpectedReply.into());
}
Err(e) => {
error!("aux packet error ({})", e);
return Err(e.into());
}
}
}
Ok(())
}
pub async fn set_log_filter(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
level: log::LevelFilter,
) -> Result<()> {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtSetLogLevelRequest {
destination,
log_level: level as u8,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn set_uart_log_filter(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
level: log::LevelFilter,
) -> Result<()> {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtSetUartLogLevelRequest {
destination,
log_level: level as u8,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn config_read(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
_cfg: &Rc<Config>,
key: &String,
) -> Result<()> {
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
let len = key.len();
config_key[..len].clone_from_slice(key.as_bytes());
let mut reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtConfigReadRequest {
destination: destination,
length: len as u16,
key: config_key,
},
timer,
)
.await;
let mut buffer = Vec::<u8>::new();
loop {
match reply {
Ok(Packet::CoreMgmtConfigReadReply { last, length, value }) => {
buffer.extend(&value[..length as usize]);
if last {
write_i8(stream, Reply::ConfigData as i8).await?;
write_chunk(stream, &buffer).await?;
return Ok(());
}
reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtConfigReadContinue {
destination: destination,
},
timer,
)
.await;
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
return Err(drtio::Error::UnexpectedReply.into());
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
return Err(e.into());
}
}
}
}
pub async fn config_write(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
_cfg: &Rc<Config>,
key: &String,
value: Vec<u8>,
_restart_idle: &Rc<Semaphore>,
) -> Result<()> {
let mut message = Vec::with_capacity(key.len() + value.len() + 4 * 2);
message.write_string(key).unwrap();
message.write_bytes(&value).unwrap();
match drtio::partition_data(
linkno,
aux_mutex,
routing_table,
timer,
&message,
|slice, status, len: usize| Packet::CoreMgmtConfigWriteRequest {
destination: destination,
last: status.is_last(),
length: len as u16,
data: *slice,
},
|reply| match reply {
Packet::CoreMgmtReply { succeeded: true } => Ok(()),
packet => {
error!("received unexpected aux packet: {:?}", packet);
Err(drtio::Error::UnexpectedReply)
}
},
)
.await
{
Ok(()) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn config_remove(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
_cfg: &Rc<Config>,
key: &String,
_restart_idle: &Rc<Semaphore>,
) -> Result<()> {
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
let len = key.len();
config_key[..len].clone_from_slice(key.as_bytes());
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtConfigRemoveRequest {
destination: destination,
length: len as u16,
key: config_key,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn config_erase(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
) -> Result<()> {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtConfigEraseRequest {
destination: destination,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn reboot(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
) -> Result<()> {
info!("initited reboot request to satellite destination {}", destination);
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtRebootRequest {
destination: destination,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::RebootImminent as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn debug_allocator(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
) -> Result<()> {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtAllocatorDebugRequest {
destination: destination,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
Err(e.into())
}
}
}
pub async fn image_write(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
_cfg: &Rc<Config>,
image: Vec<u8>,
) -> Result<()> {
let mut image = &image[..];
let alloc_reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtFlashRequest {
destination: destination,
payload_length: image.len() as u32,
},
timer,
)
.await;
match alloc_reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => Ok(()),
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply)
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::AuxError)
}
}?;
while !image.is_empty() {
let mut data = [0; MASTER_PAYLOAD_MAX_SIZE];
let len = image.read(&mut data).unwrap();
let last = image.is_empty();
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtFlashAddDataRequest {
destination: destination,
last: last,
length: len as u16,
data: data,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) if !last => Ok(()),
Ok(Packet::CoreMgmtDropLink) if last => drtioaux_async::send(
linkno,
&Packet::CoreMgmtDropLinkAck {
destination: destination,
},
)
.await
.map_err(|_| drtio::Error::AuxError),
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply)
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::AuxError)
}
}?;
}
write_i8(stream, Reply::RebootImminent as i8).await?;
Ok(())
}
}
mod local_coremgmt {
use libboard_zynq::slcr;
use super::*;
pub async fn get_log(stream: &mut TcpStream) -> Result<()> {
let buffer = get_logger_buffer().await.extract().as_bytes().to_vec(); let buffer = get_logger_buffer().await.extract().as_bytes().to_vec();
write_i8(stream, Reply::LogContent as i8).await?; write_i8(stream, Reply::LogContent as i8).await?;
write_chunk(stream, &buffer).await?; write_chunk(stream, &buffer).await?;
Ok(())
} }
Request::ClearLog => {
pub async fn clear_log(stream: &mut TcpStream) -> Result<()> {
let mut buffer = get_logger_buffer().await; let mut buffer = get_logger_buffer().await;
buffer.clear(); buffer.clear();
write_i8(stream, Reply::Success as i8).await?; write_i8(stream, Reply::Success as i8).await?;
Ok(())
} }
Request::PullLog => {
pub async fn pull_log(stream: &mut TcpStream, pull_id: &Rc<RefCell<u32>>) -> Result<()> {
let id = { let id = {
let mut guard = pull_id.borrow_mut(); let mut guard = pull_id.borrow_mut();
*guard += 1; *guard += 1;
@ -157,32 +749,34 @@ async fn handle_connection(
buffer.clear(); buffer.clear();
core::mem::drop(buffer); core::mem::drop(buffer);
write_chunk(stream, &bytes).await?; write_chunk(stream, &bytes).await?;
if log::max_level() == LevelFilter::Trace { if log::max_level() == log::LevelFilter::Trace {
// temporarily discard all trace level log // temporarily discard all trace level log
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() }; let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
logger.set_buffer_log_level(LevelFilter::Debug); logger.set_buffer_log_level(log::LevelFilter::Debug);
stream.flush().await?; stream.flush().await?;
logger.set_buffer_log_level(LevelFilter::Trace); logger.set_buffer_log_level(log::LevelFilter::Trace);
} }
} }
Ok(())
} }
Request::SetLogFilter => {
let lvl = read_log_level_filter(stream).await?; pub async fn set_log_filter(stream: &mut TcpStream, lvl: log::LevelFilter) -> Result<()> {
info!("Changing log level to {}", lvl); info!("Changing log level to {}", lvl);
log::set_max_level(lvl); log::set_max_level(lvl);
write_i8(stream, Reply::Success as i8).await?; write_i8(stream, Reply::Success as i8).await?;
Ok(())
} }
Request::SetUartLogFilter => {
let lvl = read_log_level_filter(stream).await?; pub async fn set_uart_log_filter(stream: &mut TcpStream, lvl: log::LevelFilter) -> Result<()> {
info!("Changing UART log level to {}", lvl); info!("Changing UART log level to {}", lvl);
unsafe { unsafe {
BufferLogger::get_logger().as_ref().unwrap().set_uart_log_level(lvl); BufferLogger::get_logger().as_ref().unwrap().set_uart_log_level(lvl);
} }
write_i8(stream, Reply::Success as i8).await?; write_i8(stream, Reply::Success as i8).await?;
Ok(())
} }
Request::ConfigRead => {
let key = read_key(stream).await?; pub async fn config_read(stream: &mut TcpStream, cfg: &Rc<Config>, key: &String) -> Result<()> {
debug!("read key: {}", key);
let value = cfg.read(&key); let value = cfg.read(&key);
if let Ok(value) = value { if let Ok(value) = value {
debug!("got value"); debug!("got value");
@ -192,18 +786,17 @@ async fn handle_connection(
warn!("read error: no such key"); warn!("read error: no such key");
write_i8(stream, Reply::Error as i8).await?; write_i8(stream, Reply::Error as i8).await?;
} }
Ok(())
} }
Request::ConfigWrite => {
let key = read_key(stream).await?; pub async fn config_write(
debug!("write key: {}", key); stream: &mut TcpStream,
let len = read_i32(stream).await?; cfg: &Rc<Config>,
let len = if len <= 0 { 0 } else { len as usize }; key: &String,
let mut buffer = Vec::with_capacity(len); value: Vec<u8>,
unsafe { restart_idle: &Rc<Semaphore>,
buffer.set_len(len); ) -> Result<()> {
} let value = cfg.write(&key, value);
read_chunk(stream, &mut buffer).await?;
let value = cfg.write(&key, buffer);
if value.is_ok() { if value.is_ok() {
debug!("write success"); debug!("write success");
if key == "idle_kernel" { if key == "idle_kernel" {
@ -215,9 +808,15 @@ async fn handle_connection(
error!("failed to write: {:?}", value); error!("failed to write: {:?}", value);
write_i8(stream, Reply::Error as i8).await?; write_i8(stream, Reply::Error as i8).await?;
} }
Ok(())
} }
Request::ConfigRemove => {
let key = read_key(stream).await?; pub async fn config_remove(
stream: &mut TcpStream,
cfg: &Rc<Config>,
key: &String,
restart_idle: &Rc<Semaphore>,
) -> Result<()> {
debug!("erase key: {}", key); debug!("erase key: {}", key);
let value = cfg.remove(&key); let value = cfg.remove(&key);
if value.is_ok() { if value.is_ok() {
@ -230,18 +829,179 @@ async fn handle_connection(
warn!("erase failed"); warn!("erase failed");
write_i8(stream, Reply::Error as i8).await?; write_i8(stream, Reply::Error as i8).await?;
} }
Ok(())
} }
Request::Reboot => {
pub async fn config_erase(stream: &mut TcpStream) -> Result<()> {
error!("zynq device does not support config erase");
write_i8(stream, Reply::Error as i8).await?;
Ok(())
}
pub async fn reboot(stream: &mut TcpStream) -> Result<()> {
info!("rebooting"); info!("rebooting");
write_i8(stream, Reply::RebootImminent as i8).await?; write_i8(stream, Reply::RebootImminent as i8).await?;
stream.flush().await?; stream.flush().await?;
slcr::reboot(); slcr::reboot();
unreachable!()
} }
pub async fn debug_allocator(_stream: &mut TcpStream) -> Result<()> {
error!("zynq device does not support allocator debug print");
Ok(())
} }
pub async fn image_write(stream: &mut TcpStream, cfg: &Rc<Config>, image: Vec<u8>) -> Result<()> {
let mut image = image.clone();
let image_ref = &image[..];
let bin_len = image.len() - 4;
let (image_ref, expected_crc) = {
let (image_ref, crc_slice) = image_ref.split_at(bin_len);
(image_ref, NativeEndian::read_u32(crc_slice))
};
let actual_crc = crc32::checksum_ieee(image_ref);
if actual_crc == expected_crc {
info!("CRC passed. Writing boot image to SD card...");
image.truncate(bin_len);
cfg.write("boot", image).expect("failed to write boot image");
reboot(stream).await?;
} else {
error!(
"CRC failed, images have not been written to flash.\n(actual {:08x}, expected {:08x})",
actual_crc, expected_crc
);
write_i8(stream, Reply::Error as i8).await?;
}
Ok(())
} }
} }
pub fn start(cfg: Rc<Config>, restart_idle: Rc<Semaphore>) { #[cfg(has_drtio)]
macro_rules! process {
($stream: ident, $drtio_tuple:ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
if $destination == 0 {
local_coremgmt::$func($stream, $($param, )*).await
} else if let Some(DrtioTuple(ref aux_mutex, ref routing_table, timer)) = $drtio_tuple {
let routing_table = routing_table.borrow();
let linkno = routing_table.0[$destination as usize][0] - 1 as u8;
remote_coremgmt::$func($stream, &aux_mutex, &routing_table, timer, linkno, $destination, $($param, )*).await
} else {
error!("coremgmt-over-drtio not supported for panicked device, please reboot");
write_i8($stream, Reply::Error as i8).await?;
Err(drtio::Error::LinkDown.into())
}
}}
}
#[cfg(not(has_drtio))]
macro_rules! process {
($stream: ident, $drtio_tuple:ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
local_coremgmt::$func($stream, $($param, )*).await
}}
}
#[derive(Clone)]
pub struct DrtioTuple(pub Rc<Mutex<bool>>, pub Rc<RefCell<RoutingTable>>, pub GlobalTimer);
async fn handle_connection(
stream: &mut TcpStream,
pull_id: Rc<RefCell<u32>>,
cfg: Rc<Config>,
restart_idle: Rc<Semaphore>,
_drtio_tuple: Option<DrtioTuple>,
) -> Result<()> {
if !expect(&stream, b"ARTIQ management\n").await? {
return Err(Error::UnexpectedPattern);
}
let _destination: u8 = read_i8(stream).await? as u8;
stream.send_slice("e".as_bytes()).await?;
loop {
let msg = read_i8(stream).await;
if let Err(smoltcp::Error::Finished) = msg {
return Ok(());
}
let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?;
match msg {
Request::GetLog => process!(stream, _drtio_tuple, _destination, get_log),
Request::ClearLog => process!(stream, _drtio_tuple, _destination, clear_log),
Request::PullLog => process!(stream, _drtio_tuple, _destination, pull_log, &pull_id),
Request::SetLogFilter => {
let lvl = read_log_level_filter(stream).await?;
process!(stream, _drtio_tuple, _destination, set_log_filter, lvl)
}
Request::SetUartLogFilter => {
let lvl = read_log_level_filter(stream).await?;
process!(stream, _drtio_tuple, _destination, set_uart_log_filter, lvl)
}
Request::ConfigRead => {
let key = read_key(stream).await?;
process!(stream, _drtio_tuple, _destination, config_read, &cfg, &key)
}
Request::ConfigWrite => {
let key = read_key(stream).await?;
let len = read_i32(stream).await?;
let len = if len <= 0 { 0 } else { len as usize };
let mut buffer = Vec::with_capacity(len);
unsafe {
buffer.set_len(len);
}
read_chunk(stream, &mut buffer).await?;
process!(
stream,
_drtio_tuple,
_destination,
config_write,
&cfg,
&key,
buffer,
&restart_idle
)
}
Request::ConfigRemove => {
let key = read_key(stream).await?;
process!(
stream,
_drtio_tuple,
_destination,
config_remove,
&cfg,
&key,
&restart_idle
)
}
Request::Reboot => {
process!(stream, _drtio_tuple, _destination, reboot)
}
Request::ConfigErase => {
process!(stream, _drtio_tuple, _destination, config_erase)
}
Request::DebugAllocator => {
process!(stream, _drtio_tuple, _destination, debug_allocator)
}
Request::Flash => {
let len = read_i32(stream).await?;
if len <= 0 {
write_i8(stream, Reply::Error as i8).await?;
return Err(Error::UnexpectedPattern);
}
let mut buffer = Vec::with_capacity(len as usize);
unsafe {
buffer.set_len(len as usize);
}
read_chunk(stream, &mut buffer).await?;
process!(stream, _drtio_tuple, _destination, image_write, &cfg, buffer)
}
}?;
}
}
pub fn start(cfg: Rc<Config>, restart_idle: Rc<Semaphore>, drtio_tuple: Option<DrtioTuple>) {
task::spawn(async move { task::spawn(async move {
let pull_id = Rc::new(RefCell::new(0u32)); let pull_id = Rc::new(RefCell::new(0u32));
loop { loop {
@ -249,9 +1009,10 @@ pub fn start(cfg: Rc<Config>, restart_idle: Rc<Semaphore>) {
let pull_id = pull_id.clone(); let pull_id = pull_id.clone();
let cfg = cfg.clone(); let cfg = cfg.clone();
let restart_idle = restart_idle.clone(); let restart_idle = restart_idle.clone();
let drtio_tuple = drtio_tuple.clone();
task::spawn(async move { task::spawn(async move {
info!("received connection"); info!("received connection");
let _ = handle_connection(&mut stream, pull_id, cfg, restart_idle) let _ = handle_connection(&mut stream, pull_id, cfg, restart_idle, drtio_tuple)
.await .await
.map_err(|e| warn!("connection terminated: {:?}", e)); .map_err(|e| warn!("connection terminated: {:?}", e));
let _ = stream.flush().await; let _ = stream.flush().await;

View File

@ -540,7 +540,7 @@ pub mod drtio {
} }
} }
async fn partition_data<PacketF, HandlerF>( pub async fn partition_data<PacketF, HandlerF>(
linkno: u8, linkno: u8,
aux_mutex: &Rc<Mutex<bool>>, aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable, routing_table: &RoutingTable,

View File

@ -15,7 +15,9 @@ build_zynq = { path = "../libbuild_zynq" }
[dependencies] [dependencies]
log = { version = "0.4", default-features = false } log = { version = "0.4", default-features = false }
byteorder = { version = "1.3", default-features = false }
core_io = { version = "0.1", features = ["collections"] } core_io = { version = "0.1", features = ["collections"] }
crc = { version = "1.7", default-features = false }
cslice = "0.3" cslice = "0.3"
embedded-hal = "0.2" embedded-hal = "0.2"

View File

@ -4,7 +4,9 @@
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate byteorder;
extern crate core_io; extern crate core_io;
extern crate crc;
extern crate cslice; extern crate cslice;
extern crate embedded_hal; extern crate embedded_hal;
@ -38,16 +40,18 @@ use libboard_artiq::{drtio_routing, drtioaux,
pl::csr}; pl::csr};
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED; use libboard_zynq::error_led::ErrorLED;
use libboard_zynq::{i2c::I2c, print, println, time::Milliseconds, timer::GlobalTimer}; use libboard_zynq::{i2c::I2c, print, println, slcr, time::Milliseconds, timer::GlobalTimer};
use libconfig::Config; use libconfig::Config;
use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR}; use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR};
use libregister::RegisterR; use libregister::RegisterR;
use libsupport_zynq::{exception_vectors, ram}; use libsupport_zynq::{exception_vectors, ram};
use mgmt::Manager as CoreManager;
use routing::Router; use routing::Router;
use subkernel::Manager as KernelManager; use subkernel::Manager as KernelManager;
mod analyzer; mod analyzer;
mod dma; mod dma;
mod mgmt;
mod repeater; mod repeater;
mod routing; mod routing;
mod subkernel; mod subkernel;
@ -149,6 +153,7 @@ fn process_aux_packet(
dma_manager: &mut DmaManager, dma_manager: &mut DmaManager,
analyzer: &mut Analyzer, analyzer: &mut Analyzer,
kernel_manager: &mut KernelManager, kernel_manager: &mut KernelManager,
core_manager: &mut CoreManager,
router: &mut Router, router: &mut Router,
) -> Result<(), drtioaux::Error> { ) -> Result<(), drtioaux::Error> {
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
@ -1010,6 +1015,335 @@ fn process_aux_packet(
} }
Ok(()) Ok(())
} }
drtioaux::Packet::CoreMgmtGetLogRequest {
destination: _destination,
clear,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut data_slice = [0; SAT_PAYLOAD_MAX_SIZE];
let meta = core_manager.log_get_slice(&mut data_slice, clear);
drtioaux::send(
0,
&drtioaux::Packet::CoreMgmtGetLogReply {
last: meta.status.is_last(),
length: meta.len as u16,
data: data_slice,
},
)
}
drtioaux::Packet::CoreMgmtClearLogRequest {
destination: _destination,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
mgmt::clear_log();
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
}
drtioaux::Packet::CoreMgmtSetLogLevelRequest {
destination: _destination,
log_level,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) {
info!("Changing log level to {}", level_filter);
log::set_max_level(level_filter);
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
} else {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
}
drtioaux::Packet::CoreMgmtSetUartLogLevelRequest {
destination: _destination,
log_level,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) {
info!("Changing UART log level to {}", level_filter);
unsafe {
logger::BufferLogger::get_logger()
.as_ref()
.unwrap()
.set_uart_log_level(level_filter);
}
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
} else {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
}
drtioaux::Packet::CoreMgmtConfigReadRequest {
destination: _destination,
length,
key,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut value_slice = [0; SAT_PAYLOAD_MAX_SIZE];
let key_slice = &key[..length as usize];
if !key_slice.is_ascii() {
error!("invalid key");
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
} else {
let key = core::str::from_utf8(key_slice).unwrap();
if core_manager.fetch_config_value(key).is_ok() {
let meta = core_manager.get_config_value_slice(&mut value_slice);
drtioaux::send(
0,
&drtioaux::Packet::CoreMgmtConfigReadReply {
last: meta.status.is_last(),
length: meta.len as u16,
value: value_slice,
},
)
} else {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
}
}
drtioaux::Packet::CoreMgmtConfigReadContinue {
destination: _destination,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut value_slice = [0; SAT_PAYLOAD_MAX_SIZE];
let meta = core_manager.get_config_value_slice(&mut value_slice);
drtioaux::send(
0,
&drtioaux::Packet::CoreMgmtConfigReadReply {
last: meta.status.is_last(),
length: meta.len as u16,
value: value_slice,
},
)
}
drtioaux::Packet::CoreMgmtConfigWriteRequest {
destination: _destination,
last,
length,
data,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
core_manager.add_config_data(&data, length as usize);
let mut succeeded = true;
if last {
succeeded = core_manager.write_config().is_ok();
core_manager.clear_config_data();
}
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded })
}
drtioaux::Packet::CoreMgmtConfigRemoveRequest {
destination: _destination,
length,
key,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let key_slice = &key[..length as usize];
if !key_slice.is_ascii() {
error!("invalid key");
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
} else {
let key = core::str::from_utf8(key_slice).unwrap();
let succeeded = core_manager.remove_config(key).is_ok();
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded })
}
}
drtioaux::Packet::CoreMgmtConfigEraseRequest {
destination: _destination,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
error!("config erase not supported on zynq device");
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
drtioaux::Packet::CoreMgmtRebootRequest {
destination: _destination,
} => {
info!("received reboot request");
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })?;
info!("reboot imminent");
slcr::reboot();
unreachable!();
}
drtioaux::Packet::CoreMgmtAllocatorDebugRequest {
destination: _destination,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
error!("debug allocator not supported on zynq device");
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
drtioaux::Packet::CoreMgmtFlashRequest {
destination: _destination,
payload_length,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
core_manager.allocate_image_buffer(payload_length as usize);
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
}
drtioaux::Packet::CoreMgmtFlashAddDataRequest {
destination: _destination,
last,
length,
data,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
core_manager.add_image_data(&data, length as usize);
if last {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtDropLink)
} else {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
}
}
drtioaux::Packet::CoreMgmtDropLinkAck {
destination: _destination,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
unsafe {
csr::gt_drtio::txenable_write(0);
}
core_manager.write_image();
info!("reboot imminent");
slcr::reboot();
Ok(())
}
p => { p => {
warn!("received unexpected aux packet: {:?}", p); warn!("received unexpected aux packet: {:?}", p);
@ -1028,6 +1362,7 @@ fn process_aux_packets(
dma_manager: &mut DmaManager, dma_manager: &mut DmaManager,
analyzer: &mut Analyzer, analyzer: &mut Analyzer,
kernel_manager: &mut KernelManager, kernel_manager: &mut KernelManager,
core_manager: &mut CoreManager,
router: &mut Router, router: &mut Router,
) { ) {
let result = drtioaux::recv(0).and_then(|packet| { let result = drtioaux::recv(0).and_then(|packet| {
@ -1043,6 +1378,7 @@ fn process_aux_packets(
dma_manager, dma_manager,
analyzer, analyzer,
kernel_manager, kernel_manager,
core_manager,
router, router,
) )
} else { } else {
@ -1239,7 +1575,7 @@ pub extern "C" fn main_core0() -> i32 {
#[cfg(has_si549)] #[cfg(has_si549)]
si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549"); si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
let cfg = match Config::new() { let mut cfg = match Config::new() {
Ok(cfg) => cfg, Ok(cfg) => cfg,
Err(err) => { Err(err) => {
warn!("config initialization failed: {}", err); warn!("config initialization failed: {}", err);
@ -1314,6 +1650,7 @@ pub extern "C" fn main_core0() -> i32 {
let mut dma_manager = DmaManager::new(); let mut dma_manager = DmaManager::new();
let mut analyzer = Analyzer::new(); let mut analyzer = Analyzer::new();
let mut kernel_manager = KernelManager::new(&mut control); let mut kernel_manager = KernelManager::new(&mut control);
let mut core_manager = CoreManager::new(&mut cfg);
drtioaux::reset(0); drtioaux::reset(0);
drtiosat_reset(false); drtiosat_reset(false);
@ -1331,6 +1668,7 @@ pub extern "C" fn main_core0() -> i32 {
&mut dma_manager, &mut dma_manager,
&mut analyzer, &mut analyzer,
&mut kernel_manager, &mut kernel_manager,
&mut core_manager,
&mut router, &mut router,
); );
#[allow(unused_mut)] #[allow(unused_mut)]

149
src/satman/src/mgmt.rs Normal file
View File

@ -0,0 +1,149 @@
use alloc::vec::Vec;
use byteorder::{ByteOrder, NativeEndian};
use crc::crc32;
use io::{ProtoRead, ProtoWrite};
use libboard_artiq::{drtioaux_proto::SAT_PAYLOAD_MAX_SIZE,
logger::{BufferLogger, LogBufferRef}};
use libconfig::Config;
use log::{debug, error, info, warn, LevelFilter};
use crate::routing::{SliceMeta, Sliceable};
type Result<T> = core::result::Result<T, ()>;
pub fn byte_to_level_filter(level_byte: u8) -> Result<LevelFilter> {
Ok(match level_byte {
0 => LevelFilter::Off,
1 => LevelFilter::Error,
2 => LevelFilter::Warn,
3 => LevelFilter::Info,
4 => LevelFilter::Debug,
5 => LevelFilter::Trace,
lv => {
error!("unknown log level: {}", lv);
return Err(());
}
})
}
fn get_logger_buffer() -> LogBufferRef<'static> {
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
loop {
if let Some(buffer_ref) = logger.buffer() {
return buffer_ref;
}
}
}
pub fn clear_log() {
let mut buffer = get_logger_buffer();
buffer.clear();
}
pub struct Manager<'a> {
cfg: &'a mut Config,
last_log: Sliceable,
config_payload: Vec<u8>,
last_value: Sliceable,
image_payload: Vec<u8>,
}
impl<'a> Manager<'_> {
pub fn new(cfg: &mut Config) -> Manager {
Manager {
cfg: cfg,
last_log: Sliceable::new(0, Vec::new()),
config_payload: Vec::new(),
last_value: Sliceable::new(0, Vec::new()),
image_payload: Vec::new(),
}
}
pub fn log_get_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE], consume: bool) -> SliceMeta {
// Populate buffer if depleted
if self.last_log.at_end() {
let mut buffer = get_logger_buffer();
self.last_log.extend(buffer.extract().as_bytes());
if consume {
buffer.clear();
}
}
self.last_log.get_slice_satellite(data_slice)
}
pub fn fetch_config_value(&mut self, key: &str) -> Result<()> {
self.cfg
.read(&key)
.map(|value| {
debug!("got value");
self.last_value = Sliceable::new(0, value)
})
.map_err(|_| warn!("read error: no such key"))
}
pub fn get_config_value_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta {
self.last_value.get_slice_satellite(data_slice)
}
pub fn add_config_data(&mut self, data: &[u8], data_len: usize) {
self.config_payload.write_all(&data[..data_len]).unwrap();
}
pub fn clear_config_data(&mut self) {
self.config_payload.clear();
}
pub fn write_config(&mut self) -> Result<()> {
let mut payload = &self.config_payload[..];
let key = payload.read_string().map_err(|_err| error!("error on reading key"))?;
debug!("write key: {}", key);
let value = payload.read_bytes().unwrap();
self.cfg
.write(&key, value)
.map(|()| debug!("write success"))
.map_err(|err| error!("failed to write: {:?}", err))
}
pub fn remove_config(&mut self, key: &str) -> Result<()> {
debug!("erase key: {}", key);
self.cfg
.remove(&key)
.map(|()| debug!("erase success"))
.map_err(|err| warn!("failed to erase: {:?}", err))
}
pub fn allocate_image_buffer(&mut self, image_size: usize) {
self.image_payload = Vec::with_capacity(image_size);
}
pub fn add_image_data(&mut self, data: &[u8], data_len: usize) {
self.image_payload.extend(&data[..data_len]);
}
pub fn write_image(&self) {
let mut image = self.image_payload.clone();
let image_ref = &image[..];
let bin_len = image.len() - 4;
let (image_ref, expected_crc) = {
let (image_ref, crc_slice) = image_ref.split_at(bin_len);
(image_ref, NativeEndian::read_u32(crc_slice))
};
let actual_crc = crc32::checksum_ieee(image_ref);
if actual_crc == expected_crc {
info!("CRC passed. Writing boot image to SD card...");
image.truncate(bin_len);
self.cfg.write("boot", image).expect("failed to write boot image");
} else {
panic!(
"CRC failed, images have not been written to flash.\n(actual {:08x}, expected {:08x})",
actual_crc, expected_crc
);
}
}
}

View File

@ -4,7 +4,7 @@ use core::cmp::min;
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
use libboard_artiq::pl::csr; use libboard_artiq::pl::csr;
use libboard_artiq::{drtio_routing, drtioaux, use libboard_artiq::{drtio_routing, drtioaux,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}}; drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE}};
pub struct SliceMeta { pub struct SliceMeta {
pub destination: u8, pub destination: u8,
@ -58,6 +58,7 @@ impl Sliceable {
} }
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE); get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
get_slice_fn!(get_slice_satellite, SAT_PAYLOAD_MAX_SIZE);
} }
// Packets from downstream (further satellites) are received and routed appropriately. // Packets from downstream (further satellites) are received and routed appropriately.