2016-09-27 21:36:55 +08:00
|
|
|
use std::prelude::v1::*;
|
2016-09-29 02:25:25 +08:00
|
|
|
use std::str;
|
2016-10-01 12:20:27 +08:00
|
|
|
use std::io::{self, Read};
|
|
|
|
use {config, rtio_crg, clock, mailbox, kernel};
|
2016-09-30 04:56:35 +08:00
|
|
|
use logger::BufferLogger;
|
|
|
|
use sched::{Waiter, TcpListener, TcpStream, SocketAddr, IP_ANY};
|
2016-09-27 21:36:55 +08:00
|
|
|
|
2016-10-01 12:20:27 +08:00
|
|
|
use session_proto as host;
|
|
|
|
use kernel_proto as kern;
|
|
|
|
|
|
|
|
macro_rules! unexpected {
|
|
|
|
($($arg:tt)*) => {
|
|
|
|
{
|
|
|
|
error!($($arg)*);
|
|
|
|
return Err(io::Error::new(io::ErrorKind::InvalidData, "protocol error"))
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-10-02 00:26:57 +08:00
|
|
|
fn io_error(msg: &str) -> io::Error {
|
|
|
|
io::Error::new(io::ErrorKind::Other, msg)
|
|
|
|
}
|
|
|
|
|
2016-10-01 12:20:27 +08:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
2016-09-27 21:36:55 +08:00
|
|
|
enum KernelState {
|
|
|
|
Absent,
|
|
|
|
Loaded,
|
|
|
|
Running,
|
|
|
|
RpcWait
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Session {
|
|
|
|
kernel_state: KernelState,
|
2016-10-01 12:20:27 +08:00
|
|
|
watchdog_set: clock::WatchdogSet,
|
|
|
|
now: u64
|
2016-09-27 21:36:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Session {
|
2016-09-30 04:36:04 +08:00
|
|
|
pub fn new() -> Session {
|
2016-09-27 21:36:55 +08:00
|
|
|
Session {
|
2016-10-01 12:20:27 +08:00
|
|
|
kernel_state: KernelState::Absent,
|
|
|
|
watchdog_set: clock::WatchdogSet::new(),
|
|
|
|
now: 0
|
2016-09-27 21:36:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-30 04:36:04 +08:00
|
|
|
pub fn running(&self) -> bool {
|
|
|
|
match self.kernel_state {
|
|
|
|
KernelState::Absent | KernelState::Loaded => false,
|
|
|
|
KernelState::Running | KernelState::RpcWait => true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-02 00:26:57 +08:00
|
|
|
impl Drop for Session {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
kernel::stop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-30 04:56:35 +08:00
|
|
|
fn check_magic(stream: &mut TcpStream) -> io::Result<()> {
|
2016-09-27 21:36:55 +08:00
|
|
|
const MAGIC: &'static [u8] = b"ARTIQ coredev\n";
|
|
|
|
|
|
|
|
let mut magic: [u8; 14] = [0; 14];
|
|
|
|
try!(stream.read_exact(&mut magic));
|
|
|
|
if magic != MAGIC {
|
|
|
|
Err(io::Error::new(io::ErrorKind::InvalidData, "unrecognized magic"))
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-01 12:20:27 +08:00
|
|
|
fn host_read(stream: &mut TcpStream) -> io::Result<host::Request> {
|
|
|
|
let request = try!(host::Request::read_from(stream));
|
|
|
|
match &request {
|
|
|
|
&host::Request::LoadLibrary(_) => trace!("comm<-host LoadLibrary(...)"),
|
|
|
|
_ => trace!("comm<-host {:?}", request)
|
2016-09-27 21:36:55 +08:00
|
|
|
}
|
2016-10-01 12:20:27 +08:00
|
|
|
Ok(request)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn host_write(stream: &mut TcpStream, reply: host::Reply) -> io::Result<()> {
|
|
|
|
trace!("comm->host {:?}", reply);
|
|
|
|
reply.write_to(stream)
|
|
|
|
}
|
2016-09-27 21:36:55 +08:00
|
|
|
|
2016-10-01 12:20:27 +08:00
|
|
|
fn kern_send<'a>(waiter: Waiter, request: kern::Message<'a>) -> io::Result<()> {
|
|
|
|
match &request {
|
|
|
|
&kern::LoadRequest(_) => trace!("comm->kern LoadRequest(...)"),
|
|
|
|
_ => trace!("comm->kern {:?}", request)
|
2016-09-27 21:36:55 +08:00
|
|
|
}
|
2016-10-01 12:20:27 +08:00
|
|
|
request.send_and_wait(waiter)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn kern_recv<R, F>(waiter: Waiter, f: F) -> io::Result<R>
|
|
|
|
where F: FnOnce(kern::Message) -> io::Result<R> {
|
|
|
|
kern::Message::wait_and_receive(waiter, |reply| {
|
|
|
|
trace!("comm<-kern {:?}", reply);
|
|
|
|
f(reply)
|
|
|
|
})
|
|
|
|
}
|
2016-09-27 21:36:55 +08:00
|
|
|
|
2016-10-01 12:20:27 +08:00
|
|
|
fn kern_acknowledge() -> io::Result<()> {
|
|
|
|
kern::Message::acknowledge();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn comm_handle(waiter: Waiter,
|
|
|
|
stream: &mut TcpStream,
|
|
|
|
logger: &BufferLogger,
|
|
|
|
session: &mut Session) -> io::Result<()> {
|
|
|
|
match try!(host_read(stream)) {
|
|
|
|
host::Request::Ident =>
|
|
|
|
host_write(stream, host::Reply::Ident(::board::ident(&mut [0; 64]))),
|
2016-09-29 02:25:25 +08:00
|
|
|
|
2016-09-30 04:36:04 +08:00
|
|
|
// artiq_corelog
|
2016-10-01 12:20:27 +08:00
|
|
|
host::Request::Log => {
|
2016-09-29 02:25:25 +08:00
|
|
|
// Logging the packet with the log is inadvisable
|
|
|
|
trace!("comm->host Log(...)");
|
|
|
|
logger.extract(move |log| {
|
2016-10-01 12:20:27 +08:00
|
|
|
host::Reply::Log(log).write_to(stream)
|
2016-09-29 02:25:25 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-10-01 12:20:27 +08:00
|
|
|
host::Request::LogClear => {
|
2016-09-29 02:25:25 +08:00
|
|
|
logger.clear();
|
2016-10-01 12:20:27 +08:00
|
|
|
host_write(stream, host::Reply::Log(""))
|
2016-09-29 02:25:25 +08:00
|
|
|
}
|
|
|
|
|
2016-09-30 04:36:04 +08:00
|
|
|
// artiq_coreconfig
|
2016-10-01 12:20:27 +08:00
|
|
|
host::Request::FlashRead { ref key } => {
|
2016-09-30 02:54:08 +08:00
|
|
|
let value = config::read_to_end(key);
|
2016-10-01 12:20:27 +08:00
|
|
|
host_write(stream, host::Reply::FlashRead(&value))
|
2016-09-30 02:54:08 +08:00
|
|
|
}
|
|
|
|
|
2016-10-01 12:20:27 +08:00
|
|
|
host::Request::FlashWrite { ref key, ref value } => {
|
2016-09-30 02:54:08 +08:00
|
|
|
match config::write(key, value) {
|
2016-10-01 12:20:27 +08:00
|
|
|
Ok(_) => host_write(stream, host::Reply::FlashOk),
|
|
|
|
Err(_) => host_write(stream, host::Reply::FlashError)
|
2016-09-30 02:54:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-01 12:20:27 +08:00
|
|
|
host::Request::FlashRemove { ref key } => {
|
2016-09-30 02:54:08 +08:00
|
|
|
config::remove(key);
|
2016-10-01 12:20:27 +08:00
|
|
|
host_write(stream, host::Reply::FlashOk)
|
2016-09-30 02:54:08 +08:00
|
|
|
}
|
|
|
|
|
2016-10-01 12:20:27 +08:00
|
|
|
host::Request::FlashErase => {
|
2016-09-30 02:54:08 +08:00
|
|
|
config::erase();
|
2016-10-01 12:20:27 +08:00
|
|
|
host_write(stream, host::Reply::FlashOk)
|
2016-09-30 02:54:08 +08:00
|
|
|
}
|
|
|
|
|
2016-09-30 04:36:04 +08:00
|
|
|
// artiq_run/artiq_master
|
2016-10-01 12:20:27 +08:00
|
|
|
host::Request::SwitchClock(clk) => {
|
2016-09-30 04:36:04 +08:00
|
|
|
if session.running() {
|
2016-10-01 12:20:27 +08:00
|
|
|
error!("attempted to switch RTIO clock while a kernel was running");
|
|
|
|
return host_write(stream, host::Reply::ClockSwitchFailed)
|
|
|
|
}
|
|
|
|
|
|
|
|
if rtio_crg::switch_clock(clk) {
|
|
|
|
host_write(stream, host::Reply::ClockSwitchCompleted)
|
2016-09-30 04:36:04 +08:00
|
|
|
} else {
|
2016-10-01 12:20:27 +08:00
|
|
|
host_write(stream, host::Reply::ClockSwitchFailed)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
host::Request::LoadLibrary(library) => {
|
|
|
|
if session.running() {
|
|
|
|
error!("attempted to load a new kernel while a kernel was running");
|
|
|
|
return host_write(stream, host::Reply::LoadFailed)
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe { kernel::start() }
|
|
|
|
|
|
|
|
try!(kern_send(waiter, kern::LoadRequest(&library)));
|
|
|
|
kern_recv(waiter, |reply| {
|
|
|
|
match reply {
|
|
|
|
kern::LoadReply { error: None } => {
|
|
|
|
session.kernel_state = KernelState::Loaded;
|
|
|
|
host_write(stream, host::Reply::LoadCompleted)
|
|
|
|
}
|
|
|
|
kern::LoadReply { error: Some(cause) } => {
|
|
|
|
error!("cannot load kernel: {}", cause);
|
|
|
|
host_write(stream, host::Reply::LoadFailed)
|
|
|
|
}
|
|
|
|
other => unexpected!("unexpected reply from kernel CPU: {:?}", other)
|
2016-09-30 04:36:04 +08:00
|
|
|
}
|
2016-10-01 12:20:27 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
host::Request::RunKernel => {
|
|
|
|
if session.kernel_state != KernelState::Loaded {
|
|
|
|
error!("attempted to run a kernel while not in Loaded state");
|
|
|
|
return host_write(stream, host::Reply::KernelStartupFailed)
|
2016-09-30 04:36:04 +08:00
|
|
|
}
|
2016-10-01 12:20:27 +08:00
|
|
|
|
|
|
|
session.kernel_state = KernelState::Running;
|
2016-10-02 00:07:45 +08:00
|
|
|
// TODO: make this a separate request
|
2016-10-01 12:20:27 +08:00
|
|
|
kern_acknowledge()
|
2016-09-30 04:36:04 +08:00
|
|
|
}
|
|
|
|
|
2016-10-02 00:07:45 +08:00
|
|
|
request => unexpected!("unexpected request {:?} from host machine", request)
|
2016-09-27 21:36:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-01 12:20:27 +08:00
|
|
|
fn kern_handle(waiter: Waiter,
|
|
|
|
stream: &mut TcpStream,
|
|
|
|
session: &mut Session) -> io::Result<()> {
|
|
|
|
kern::Message::wait_and_receive(waiter, |request| {
|
|
|
|
match (&request, session.kernel_state) {
|
|
|
|
(&kern::LoadReply { .. }, KernelState::Loaded) |
|
|
|
|
(&kern::RpcRecvRequest { .. }, KernelState::RpcWait) => {
|
|
|
|
// We're standing by; ignore the message.
|
|
|
|
return Ok(())
|
|
|
|
}
|
|
|
|
(_, KernelState::Running) => (),
|
|
|
|
_ => {
|
|
|
|
unexpected!("unexpected request {:?} from kernel CPU in {:?} state",
|
|
|
|
request, session.kernel_state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
trace!("comm<-kern {:?}", request);
|
|
|
|
match request {
|
|
|
|
kern::Log(log) => {
|
|
|
|
info!(target: "kernel", "{}", log);
|
|
|
|
kern_acknowledge()
|
|
|
|
}
|
|
|
|
|
|
|
|
kern::NowInitRequest =>
|
|
|
|
kern_send(waiter, kern::NowInitReply(session.now)),
|
|
|
|
|
|
|
|
kern::NowSave(now) => {
|
|
|
|
session.now = now;
|
|
|
|
kern_acknowledge()
|
|
|
|
}
|
|
|
|
|
2016-10-02 00:26:57 +08:00
|
|
|
kern::WatchdogSetRequest { ms } => {
|
|
|
|
let id = try!(session.watchdog_set.set_ms(ms)
|
|
|
|
.map_err(|()| io_error("out of watchdogs")));
|
|
|
|
kern_send(waiter, kern::WatchdogSetReply { id: id })
|
|
|
|
}
|
|
|
|
|
|
|
|
kern::WatchdogClear { id } => {
|
|
|
|
session.watchdog_set.clear(id);
|
|
|
|
kern_acknowledge()
|
|
|
|
}
|
|
|
|
|
2016-10-02 00:07:45 +08:00
|
|
|
request => unexpected!("unexpected request {:?} from kernel CPU", request)
|
2016-10-01 12:20:27 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn handle(waiter: Waiter,
|
|
|
|
stream: &mut TcpStream,
|
|
|
|
logger: &BufferLogger) -> io::Result<()> {
|
2016-09-27 21:36:55 +08:00
|
|
|
try!(check_magic(stream));
|
2016-09-30 04:36:04 +08:00
|
|
|
|
|
|
|
let mut session = Session::new();
|
2016-09-27 21:36:55 +08:00
|
|
|
loop {
|
2016-10-01 12:20:27 +08:00
|
|
|
if stream.readable() {
|
|
|
|
try!(comm_handle(waiter, stream, logger, &mut session))
|
|
|
|
}
|
|
|
|
|
|
|
|
if mailbox::receive() != 0 {
|
|
|
|
try!(kern_handle(waiter, stream, &mut session))
|
|
|
|
}
|
|
|
|
|
|
|
|
if session.kernel_state == KernelState::Running {
|
|
|
|
if session.watchdog_set.expired() {
|
|
|
|
try!(host_write(stream, host::Reply::WatchdogExpired));
|
2016-10-02 00:26:57 +08:00
|
|
|
return Err(io_error("watchdog expired"))
|
2016-10-01 12:20:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if !rtio_crg::check() {
|
|
|
|
try!(host_write(stream, host::Reply::ClockFailure));
|
2016-10-02 00:26:57 +08:00
|
|
|
return Err(io_error("RTIO clock failure"))
|
2016-10-01 12:20:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
waiter.relinquish()
|
2016-09-27 21:36:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-30 04:56:35 +08:00
|
|
|
pub fn handler(waiter: Waiter,
|
|
|
|
logger: &BufferLogger) {
|
|
|
|
let addr = SocketAddr::new(IP_ANY, 1381);
|
|
|
|
let listener = TcpListener::bind(waiter, addr).unwrap();
|
2016-09-30 04:36:04 +08:00
|
|
|
info!("accepting network sessions in Rust");
|
|
|
|
|
2016-09-27 21:36:55 +08:00
|
|
|
loop {
|
2016-09-29 02:25:25 +08:00
|
|
|
let (mut stream, addr) = listener.accept().unwrap();
|
|
|
|
info!("new connection from {:?}", addr);
|
|
|
|
|
2016-10-01 12:20:27 +08:00
|
|
|
match handle(waiter, &mut stream, logger) {
|
2016-09-27 21:36:55 +08:00
|
|
|
Ok(()) => (),
|
|
|
|
Err(err) => {
|
2016-10-01 12:20:27 +08:00
|
|
|
if err.kind() == io::ErrorKind::UnexpectedEof {
|
2016-09-29 02:25:25 +08:00
|
|
|
info!("connection closed");
|
|
|
|
} else {
|
2016-10-01 12:20:27 +08:00
|
|
|
error!("session aborted: {:?}", err);
|
2016-09-29 02:25:25 +08:00
|
|
|
}
|
2016-09-27 21:36:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|