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;
|
2020-04-17 05:58:04 +08:00
|
|
|
use alloc::rc::Rc;
|
2020-06-08 13:11:09 +08:00
|
|
|
use alloc::sync::Arc;
|
2020-06-08 18:32:44 +08:00
|
|
|
use alloc::{vec, vec::Vec, string::String};
|
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,
|
2020-07-06 12:59:51 +08:00
|
|
|
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
|
|
|
};
|
2020-04-17 04:11:11 +08:00
|
|
|
use libasync::{smoltcp::{Sockets, TcpStream}, task};
|
2020-04-12 10:38:52 +08:00
|
|
|
|
2020-07-06 12:59:51 +08:00
|
|
|
use crate::net_settings;
|
2020-06-05 17:14:36 +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-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,
|
|
|
|
}
|
|
|
|
|
2020-04-17 17:05:55 +08:00
|
|
|
async fn write_header(stream: &TcpStream, reply: Reply) -> Result<()> {
|
2020-04-12 17:44:32 +08:00
|
|
|
stream.send([0x5a, 0x5a, 0x5a, 0x5a, reply.to_u8().unwrap()].iter().copied()).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()))?)
|
|
|
|
}
|
|
|
|
|
2020-06-09 13:03:08 +08:00
|
|
|
async fn handle_run_kernel(stream: &TcpStream, control: &Rc<RefCell<kernel::Control>>) -> Result<()> {
|
|
|
|
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;
|
2020-06-08 13:11:09 +08:00
|
|
|
match *reply {
|
|
|
|
kernel::Message::RpcSend { is_async, data } => {
|
2020-06-08 18:16:38 +08:00
|
|
|
write_header(stream, Reply::RPCRequest).await?;
|
|
|
|
write_bool(stream, is_async).await?;
|
2020-06-08 13:11:09 +08:00
|
|
|
stream.send(data.iter().copied()).await?;
|
|
|
|
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?;
|
2020-06-09 13:03:08 +08:00
|
|
|
let slot = match *control.borrow_mut().rx.async_recv().await {
|
|
|
|
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();
|
|
|
|
control.tx.async_send(kernel::Message::RpcRecvReply(Ok(size))).await;
|
|
|
|
match *control.rx.async_recv().await {
|
|
|
|
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?;
|
2020-07-06 15:34:49 +08:00
|
|
|
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-06-08 18:16:38 +08:00
|
|
|
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) => {
|
|
|
|
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?;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-06-08 13:11:09 +08:00
|
|
|
_ => {
|
|
|
|
panic!("unexpected message from core1 while kernel was running: {:?}", reply);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-04-17 14:43:14 +08:00
|
|
|
async fn handle_connection(stream: &TcpStream, control: Rc<RefCell<kernel::Control>>) -> Result<()> {
|
2020-06-08 18:16:38 +08:00
|
|
|
expect(stream, b"ARTIQ coredev\n").await?;
|
2020-07-05 23:46:23 +08:00
|
|
|
info!("received connection");
|
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?;
|
2020-04-12 17:44:32 +08:00
|
|
|
stream.send("ARZQ".bytes()).await?;
|
|
|
|
},
|
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?;
|
2020-06-08 13:11:09 +08:00
|
|
|
let mut control = control.borrow_mut();
|
|
|
|
control.restart();
|
|
|
|
control.tx.async_send(kernel::Message::LoadRequest(Arc::new(buffer))).await;
|
|
|
|
let reply = control.rx.async_recv().await;
|
|
|
|
match *reply {
|
2020-06-08 18:16:38 +08:00
|
|
|
kernel::Message::LoadCompleted => write_header(stream, Reply::LoadCompleted).await?,
|
2020-06-08 13:11:09 +08:00
|
|
|
kernel::Message::LoadFailed => {
|
2020-06-08 18:16:38 +08:00
|
|
|
write_header(stream, Reply::LoadFailed).await?;
|
|
|
|
write_chunk(stream, b"core1 failed to process data").await?;
|
2020-06-08 13:11:09 +08:00
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
error!("unexpected message from core1: {:?}", reply);
|
2020-06-08 18:16:38 +08:00
|
|
|
write_header(stream, Reply::LoadFailed).await?;
|
|
|
|
write_chunk(stream, b"core1 sent unexpected reply").await?;
|
2020-04-17 17:05:55 +08:00
|
|
|
}
|
2020-04-17 14:43:50 +08:00
|
|
|
}
|
2020-04-26 09:57:42 +08:00
|
|
|
},
|
|
|
|
Request::RunKernel => {
|
2020-06-09 13:03:08 +08:00
|
|
|
handle_run_kernel(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-04-25 12:59:57 +08:00
|
|
|
pub fn main(timer: GlobalTimer) {
|
2020-07-06 12:59:51 +08:00
|
|
|
let net_addresses = net_settings::get_adresses();
|
|
|
|
info!("network addresses: {}", net_addresses);
|
|
|
|
|
|
|
|
let eth = zynq::eth::Eth::default(net_addresses.hardware_addr.0.clone());
|
2020-04-12 10:38:52 +08:00
|
|
|
const RX_LEN: usize = 8;
|
|
|
|
// Number of transmission buffers (minimum is two because with
|
|
|
|
// one, duplicate packet transmission occurs)
|
|
|
|
const TX_LEN: usize = 8;
|
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
|
|
|
|
2020-07-06 12:59:51 +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-04-28 19:46:33 +08:00
|
|
|
let control: Rc<RefCell<kernel::Control>> = Rc::new(RefCell::new(kernel::Control::start()));
|
2020-04-17 05:58:04 +08:00
|
|
|
task::spawn(async move {
|
2020-04-17 04:11:11 +08:00
|
|
|
loop {
|
2020-04-17 19:57:58 +08:00
|
|
|
let stream = TcpStream::accept(1381, 2048, 2048).await.unwrap();
|
|
|
|
let control = control.clone();
|
|
|
|
task::spawn(async {
|
|
|
|
let _ = handle_connection(&stream, control)
|
|
|
|
.await
|
2020-04-24 14:37:16 +08:00
|
|
|
.map_err(|e| warn!("connection terminated: {}", e));
|
2020-04-17 19:57:58 +08:00
|
|
|
let _ = stream.flush().await;
|
|
|
|
let _ = stream.abort().await;
|
|
|
|
});
|
2020-04-17 04:11:11 +08:00
|
|
|
}
|
2020-04-12 10:38:52 +08:00
|
|
|
});
|
|
|
|
|
2020-04-25 20:31:38 +08:00
|
|
|
moninj::start(timer);
|
2020-04-24 14:37:16 +08:00
|
|
|
|
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
|
|
|
});
|
|
|
|
}
|