artiq-zynq/src/runtime/src/comms.rs

452 lines
18 KiB
Rust
Raw Normal View History

2020-04-12 17:44:32 +08:00
use core::fmt;
2020-04-13 17:31:17 +08:00
use core::cell::RefCell;
2020-06-08 18:32:44 +08:00
use core::str::Utf8Error;
use alloc::{vec, vec::Vec, string::String, collections::BTreeMap, rc::Rc};
2020-07-05 23:46:23 +08:00
use log::{info, warn, error};
2020-04-12 17:44:32 +08:00
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::{FromPrimitive, ToPrimitive};
2020-04-12 10:38:52 +08:00
use libboard_zynq::{
self as zynq,
smoltcp::{
self,
wire::IpCidr,
iface::{NeighborCache, EthernetInterfaceBuilder},
2020-04-12 10:38:52 +08:00
time::Instant,
},
2020-04-25 12:59:57 +08:00
timer::GlobalTimer,
2020-04-12 10:38:52 +08:00
};
use libcortex_a9::{semaphore::Semaphore, mutex::Mutex, sync_channel::{Sender, Receiver}};
use futures::{select_biased, future::FutureExt};
use libasync::{smoltcp::{Sockets, TcpStream}, task};
2020-09-01 14:43:16 +08:00
use libconfig::{Config, net_settings};
2020-04-12 10:38:52 +08:00
use crate::proto_async::*;
2020-04-13 17:31:17 +08:00
use crate::kernel;
2020-06-08 13:11:09 +08:00
use crate::rpc;
2020-04-24 14:37:16 +08:00
use crate::moninj;
2020-07-13 15:00:53 +08:00
use crate::mgmt;
2020-07-16 11:47:55 +08:00
use crate::analyzer;
2020-04-13 17:31:17 +08:00
2020-04-12 10:38:52 +08:00
2020-04-12 17:44:32 +08:00
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
NetworkError(smoltcp::Error),
UnexpectedPattern,
UnrecognizedPacket,
2020-06-08 18:32:44 +08:00
BufferExhausted,
Utf8Error(Utf8Error),
2020-04-12 17:44:32 +08:00
}
pub type Result<T> = core::result::Result<T, Error>;
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
2020-06-13 16:43:32 +08:00
Error::NetworkError(error) => write!(f, "network error: {}", error),
Error::UnexpectedPattern => write!(f, "unexpected pattern"),
Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
Error::BufferExhausted => write!(f, "buffer exhausted"),
Error::Utf8Error(error) => write!(f, "UTF-8 error: {}", error),
2020-04-12 17:44:32 +08:00
}
}
}
impl From<smoltcp::Error> for Error {
fn from(error: smoltcp::Error) -> Self {
Error::NetworkError(error)
}
}
2020-04-24 14:37:16 +08:00
#[derive(Debug, FromPrimitive, ToPrimitive)]
2020-04-12 17:44:32 +08:00
enum Request {
SystemInfo = 3,
LoadKernel = 5,
RunKernel = 6,
RPCReply = 7,
RPCException = 8,
}
2020-04-24 14:37:16 +08:00
#[derive(Debug, FromPrimitive, ToPrimitive)]
2020-04-12 17:44:32 +08:00
enum Reply {
SystemInfo = 2,
LoadCompleted = 5,
LoadFailed = 6,
KernelFinished = 7,
KernelStartupFailed = 8,
KernelException = 9,
RPCRequest = 10,
WatchdogExpired = 14,
ClockFailure = 15,
}
static CACHE_STORE: Mutex<BTreeMap<String, Vec<i32>>> = Mutex::new(BTreeMap::new());
static DMA_RECORD_STORE: Mutex<BTreeMap<String, (Vec<u8>, i64)>> = Mutex::new(BTreeMap::new());
2020-04-17 17:05:55 +08:00
async fn write_header(stream: &TcpStream, reply: Reply) -> Result<()> {
stream.send_slice(&[0x5a, 0x5a, 0x5a, 0x5a, reply.to_u8().unwrap()]).await?;
2020-04-12 10:38:52 +08:00
Ok(())
}
2020-06-08 13:11:09 +08:00
async fn read_request(stream: &TcpStream, allow_close: bool) -> Result<Option<Request>> {
2020-06-08 18:16:38 +08:00
match expect(stream, &[0x5a, 0x5a, 0x5a, 0x5a]).await {
2020-06-08 13:11:09 +08:00
Ok(true) => {}
Ok(false) =>
return Err(Error::UnexpectedPattern),
Err(smoltcp::Error::Illegal) => {
if allow_close {
2020-07-05 23:46:23 +08:00
info!("peer closed connection");
2020-06-08 13:11:09 +08:00
return Ok(None);
} else {
error!("peer unexpectedly closed connection");
return Err(smoltcp::Error::Illegal)?;
}
},
Err(e) =>
return Err(e)?,
}
Ok(Some(FromPrimitive::from_i8(read_i8(&stream).await?).ok_or(Error::UnrecognizedPacket)?))
}
2020-06-08 18:32:44 +08:00
async fn read_bytes(stream: &TcpStream, max_length: usize) -> Result<Vec<u8>> {
let length = read_i32(&stream).await? as usize;
if length > max_length {
return Err(Error::BufferExhausted);
}
let mut buffer = vec![0; length];
read_chunk(&stream, &mut buffer).await?;
Ok(buffer)
}
async fn read_string(stream: &TcpStream, max_length: usize) -> Result<String> {
let bytes = read_bytes(stream, max_length).await?;
Ok(String::from_utf8(bytes).map_err(|err| Error::Utf8Error(err.utf8_error()))?)
}
const RETRY_LIMIT: usize = 100;
async fn fast_send(sender: &mut Sender<'_, kernel::Message>, content: kernel::Message) {
let mut content = content;
for _ in 0..RETRY_LIMIT {
match sender.try_send(content) {
Ok(()) => {
return
},
Err(v) => {
content = v;
}
}
}
sender.async_send(content).await;
}
async fn fast_recv(receiver: &mut Receiver<'_, kernel::Message>) -> kernel::Message {
for _ in 0..RETRY_LIMIT {
match receiver.try_recv() {
Ok(v) => {
return v;
},
Err(()) => ()
}
}
receiver.async_recv().await
}
2020-07-08 15:54:50 +08:00
async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kernel::Control>>) -> Result<()> {
2020-06-09 13:03:08 +08:00
control.borrow_mut().tx.async_send(kernel::Message::StartRequest).await;
2020-06-08 13:11:09 +08:00
loop {
2020-06-09 13:03:08 +08:00
let reply = control.borrow_mut().rx.async_recv().await;
match reply {
2020-06-08 13:11:09 +08:00
kernel::Message::RpcSend { is_async, data } => {
2020-07-08 15:54:50 +08:00
if stream.is_none() {
error!("Unexpected RPC from startup/idle kernel!");
break
}
let stream = stream.unwrap();
2020-06-08 18:16:38 +08:00
write_header(stream, Reply::RPCRequest).await?;
write_bool(stream, is_async).await?;
stream.send_slice(&data).await?;
2020-06-08 13:11:09 +08:00
if !is_async {
let host_request = read_request(stream, false).await?.unwrap();
match host_request {
Request::RPCReply => {
2020-06-08 18:16:38 +08:00
let tag = read_bytes(stream, 512).await?;
let slot = match fast_recv(&mut control.borrow_mut().rx).await {
2020-06-09 13:03:08 +08:00
kernel::Message::RpcRecvRequest(slot) => slot,
other => panic!("expected root value slot from core1, not {:?}", other),
2020-06-08 13:11:09 +08:00
};
2020-06-09 13:03:08 +08:00
rpc::recv_return(stream, &tag, slot, &|size| {
let control = control.clone();
async move {
if size == 0 {
// Don't try to allocate zero-length values, as RpcRecvReply(0) is
// used to terminate the kernel-side receive loop.
0 as *mut ()
} else {
let mut control = control.borrow_mut();
fast_send(&mut control.tx, kernel::Message::RpcRecvReply(Ok(size))).await;
match fast_recv(&mut control.rx).await {
2020-06-09 13:03:08 +08:00
kernel::Message::RpcRecvRequest(slot) => slot,
other => panic!("expected nested value slot from kernel CPU, not {:?}", other),
}
}
2020-06-08 13:11:09 +08:00
}
}).await?;
2020-06-09 13:03:08 +08:00
control.borrow_mut().tx.async_send(kernel::Message::RpcRecvReply(Ok(0))).await;
2020-06-08 13:11:09 +08:00
},
2020-06-08 18:32:44 +08:00
Request::RPCException => {
2020-06-09 13:03:08 +08:00
let mut control = control.borrow_mut();
match control.rx.async_recv().await {
2020-06-08 18:32:44 +08:00
kernel::Message::RpcRecvRequest(_) => (),
2020-06-09 13:03:08 +08:00
other => panic!("expected (ignored) root value slot from kernel CPU, not {:?}", other),
2020-06-08 18:32:44 +08:00
}
let name = read_string(stream, 16384).await?;
let message = read_string(stream, 16384).await?;
let param = [read_i64(stream).await?,
read_i64(stream).await?,
read_i64(stream).await?];
let file = read_string(stream, 16384).await?;
let line = read_i32(stream).await?;
let column = read_i32(stream).await?;
let function = read_string(stream, 16384).await?;
control.tx.async_send(kernel::Message::RpcRecvReply(Err(kernel::RPCException {
name, message, param, file, line, column, function
}))).await;
2020-06-08 18:32:44 +08:00
},
2020-06-08 13:11:09 +08:00
_ => {
error!("unexpected RPC request from host: {:?}", host_request);
return Err(Error::UnrecognizedPacket)
}
}
}
},
kernel::Message::KernelFinished => {
2020-07-08 15:54:50 +08:00
if let Some(stream) = stream {
write_header(stream, Reply::KernelFinished).await?;
}
2020-06-08 13:11:09 +08:00
break;
},
2020-07-03 17:21:42 +08:00
kernel::Message::KernelException(exception, backtrace) => {
2020-07-08 15:54:50 +08:00
match stream {
Some(stream) => {
// only send the exception data to host if there is host,
// i.e. not idle/startup kernel.
write_header(stream, Reply::KernelException).await?;
write_chunk(stream, exception.name.as_ref()).await?;
write_chunk(stream, exception.message.as_ref()).await?;
write_i64(stream, exception.param[0] as i64).await?;
write_i64(stream, exception.param[1] as i64).await?;
write_i64(stream, exception.param[2] as i64).await?;
write_chunk(stream, exception.file.as_ref()).await?;
write_i32(stream, exception.line as i32).await?;
write_i32(stream, exception.column as i32).await?;
write_chunk(stream, exception.function.as_ref()).await?;
write_i32(stream, backtrace.len() as i32).await?;
for &addr in backtrace {
write_i32(stream, addr as i32).await?;
}
},
None => {
error!("Uncaught kernel exception: {:?}", exception);
}
2020-07-03 17:21:42 +08:00
}
break;
}
kernel::Message::CachePutRequest(key, value) => {
CACHE_STORE.lock().insert(key, value);
},
kernel::Message::CacheGetRequest(key) => {
const DEFAULT: Vec<i32> = Vec::new();
let value = CACHE_STORE.lock().get(&key).unwrap_or(&DEFAULT).clone();
control.borrow_mut().tx.async_send(kernel::Message::CacheGetReply(value)).await;
},
kernel::Message::DmaPutRequest(recorder) => {
DMA_RECORD_STORE.lock().insert(recorder.name, (recorder.buffer, recorder.duration));
},
kernel::Message::DmaEraseRequest(name) => {
// prevent possible OOM when we have large DMA record replacement.
DMA_RECORD_STORE.lock().remove(&name);
},
kernel::Message::DmaGetRequest(name) => {
let result = DMA_RECORD_STORE.lock().get(&name).map(|v| v.clone());
control.borrow_mut().tx.async_send(kernel::Message::DmaGetReply(result)).await;
},
2020-06-08 13:11:09 +08:00
_ => {
panic!("unexpected message from core1 while kernel was running: {:?}", reply);
}
}
}
Ok(())
}
2020-07-08 15:54:50 +08:00
async fn load_kernel(buffer: &Vec<u8>, control: &Rc<RefCell<kernel::Control>>, stream: Option<&TcpStream>) -> Result<()> {
2020-07-08 15:54:50 +08:00
let mut control = control.borrow_mut();
control.restart();
control.tx.async_send(kernel::Message::LoadRequest(buffer.to_vec())).await;
2020-07-08 15:54:50 +08:00
let reply = control.rx.async_recv().await;
match reply {
2020-07-08 15:54:50 +08:00
kernel::Message::LoadCompleted => {
if let Some(stream) = stream {
write_header(stream, Reply::LoadCompleted).await?;
}
Ok(())
},
kernel::Message::LoadFailed => {
if let Some(stream) = stream {
write_header(stream, Reply::LoadFailed).await?;
write_chunk(stream, b"core1 failed to process data").await?;
} else {
error!("Kernel load failed");
}
Err(Error::UnexpectedPattern)
},
_ => {
error!("unexpected message from core1: {:?}", reply);
if let Some(stream) = stream {
write_header(stream, Reply::LoadFailed).await?;
write_chunk(stream, b"core1 sent unexpected reply").await?;
}
Err(Error::UnrecognizedPacket)
}
}
}
2020-04-17 14:43:14 +08:00
async fn handle_connection(stream: &TcpStream, control: Rc<RefCell<kernel::Control>>) -> Result<()> {
if !expect(stream, b"ARTIQ coredev\n").await? {
return Err(Error::UnexpectedPattern);
}
2020-04-12 17:44:32 +08:00
loop {
2020-06-08 13:11:09 +08:00
let request = read_request(stream, true).await?;
if request.is_none() {
return Ok(());
2020-04-24 14:37:16 +08:00
}
2020-06-08 13:11:09 +08:00
let request = request.unwrap();
2020-04-12 17:44:32 +08:00
match request {
Request::SystemInfo => {
2020-06-08 18:16:38 +08:00
write_header(stream, Reply::SystemInfo).await?;
stream.send_slice("ARZQ".as_bytes()).await?;
2020-04-12 17:44:32 +08:00
},
2020-04-13 17:31:17 +08:00
Request::LoadKernel => {
2020-06-08 18:16:38 +08:00
let buffer = read_bytes(stream, 1024*1024).await?;
load_kernel(&buffer, &control, Some(stream)).await?;
2020-04-26 09:57:42 +08:00
},
Request::RunKernel => {
2020-07-08 15:54:50 +08:00
handle_run_kernel(Some(stream), &control).await?;
2020-06-08 13:11:09 +08:00
},
_ => {
error!("unexpected request from host: {:?}", request);
return Err(Error::UnrecognizedPacket)
2020-04-13 17:31:17 +08:00
}
2020-04-12 17:44:32 +08:00
}
}
}
2020-09-01 14:43:16 +08:00
pub fn main(timer: GlobalTimer, cfg: &Config) {
2020-07-08 19:24:26 +08:00
let net_addresses = net_settings::get_adresses(cfg);
info!("network addresses: {}", net_addresses);
2020-08-18 01:17:15 +08:00
let eth = zynq::eth::Eth::eth0(net_addresses.hardware_addr.0.clone());
const RX_LEN: usize = 64;
2020-04-12 10:38:52 +08:00
// Number of transmission buffers (minimum is two because with
// one, duplicate packet transmission occurs)
const TX_LEN: usize = 64;
2020-06-11 17:36:23 +08:00
let eth = eth.start_rx(RX_LEN);
let mut eth = eth.start_tx(TX_LEN);
2020-04-12 10:38:52 +08:00
let neighbor_cache = NeighborCache::new(alloc::collections::BTreeMap::new());
let mut iface = match net_addresses.ipv6_addr {
Some(addr) => {
let ip_addrs = [
IpCidr::new(net_addresses.ipv4_addr, 0),
IpCidr::new(net_addresses.ipv6_ll_addr, 0),
IpCidr::new(addr, 0)
];
EthernetInterfaceBuilder::new(&mut eth)
.ethernet_addr(net_addresses.hardware_addr)
.ip_addrs(ip_addrs)
.neighbor_cache(neighbor_cache)
.finalize()
}
None => {
let ip_addrs = [
IpCidr::new(net_addresses.ipv4_addr, 0),
IpCidr::new(net_addresses.ipv6_ll_addr, 0)
];
EthernetInterfaceBuilder::new(&mut eth)
.ethernet_addr(net_addresses.hardware_addr)
.ip_addrs(ip_addrs)
.neighbor_cache(neighbor_cache)
.finalize()
}
};
2020-04-12 10:38:52 +08:00
Sockets::init(32);
2020-07-16 11:47:55 +08:00
mgmt::start();
analyzer::start();
moninj::start(timer);
2020-04-28 19:46:33 +08:00
let control: Rc<RefCell<kernel::Control>> = Rc::new(RefCell::new(kernel::Control::start()));
let idle_kernel = Rc::new(cfg.read("idle").ok());
2020-07-08 19:24:26 +08:00
if let Ok(buffer) = cfg.read("startup") {
2020-07-08 15:54:50 +08:00
info!("Loading startup kernel...");
if let Ok(()) = task::block_on(load_kernel(&buffer, &control, None)) {
2020-07-08 15:54:50 +08:00
info!("Starting startup kernel...");
let _ = task::block_on(handle_run_kernel(None, &control));
info!("Startup kernel finished!");
} else {
error!("Error loading startup kernel!");
}
}
task::spawn(async move {
let connection = Rc::new(Semaphore::new(1, 1));
let terminate = Rc::new(Semaphore::new(0, 1));
loop {
let stream = TcpStream::accept(1381, 0x10_000, 0x10_000).await.unwrap();
if connection.try_wait().is_none() {
// there is an existing connection
terminate.signal();
connection.async_wait().await;
}
2020-04-17 19:57:58 +08:00
let control = control.clone();
let idle_kernel = idle_kernel.clone();
let connection = connection.clone();
let terminate = terminate.clone();
// we make sure the value of terminate is 0 before we start
let _ = terminate.try_wait();
task::spawn(async move {
select_biased! {
_ = (async {
let _ = handle_connection(&stream, control.clone())
.await
.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(|e| warn!("error loading idle kernel"));
info!("Running idle kernel");
let _ = handle_run_kernel(None, &control)
.await.map_err(|e| warn!("error running idle kernel"));
info!("Idle kernel terminated");
}
}).fuse() => (),
_ = terminate.async_wait().fuse() => ()
}
connection.signal();
2020-04-17 19:57:58 +08:00
let _ = stream.flush().await;
let _ = stream.abort().await;
});
}
2020-04-12 10:38:52 +08:00
});
Sockets::run(&mut iface, || {
2020-04-25 12:59:57 +08:00
Instant::from_millis(timer.get_time().0 as i32)
2020-04-12 10:38:52 +08:00
});
}