forked from M-Labs/artiq
Rust: implement basic communication with kernel CPU.
This commit is contained in:
parent
1cbb187136
commit
b3b1ea71c5
|
@ -8,7 +8,7 @@ build = "build.rs"
|
||||||
walkdir = "0.1"
|
walkdir = "0.1"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "artiq_rust"
|
name = "runtime"
|
||||||
crate-type = ["staticlib"]
|
crate-type = ["staticlib"]
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
|
|
@ -122,25 +122,25 @@ extern {
|
||||||
pub fn tcp_bind(pcb: *mut tcp_pcb, ipaddr: *mut ip_addr, port: u16) -> err;
|
pub fn tcp_bind(pcb: *mut tcp_pcb, ipaddr: *mut ip_addr, port: u16) -> err;
|
||||||
pub fn tcp_listen_with_backlog(pcb: *mut tcp_pcb, backlog: u8) -> *mut tcp_pcb;
|
pub fn tcp_listen_with_backlog(pcb: *mut tcp_pcb, backlog: u8) -> *mut tcp_pcb;
|
||||||
pub fn tcp_accept(pcb: *mut tcp_pcb,
|
pub fn tcp_accept(pcb: *mut tcp_pcb,
|
||||||
accept: extern fn(arg: *mut c_void, newpcb: *mut tcp_pcb,
|
accept: Option<extern fn(arg: *mut c_void, newpcb: *mut tcp_pcb,
|
||||||
err: err) -> err);
|
err: err) -> err>);
|
||||||
pub fn tcp_connect(pcb: *mut tcp_pcb, ipaddr: *mut ip_addr, port: u16,
|
pub fn tcp_connect(pcb: *mut tcp_pcb, ipaddr: *mut ip_addr, port: u16,
|
||||||
connected: extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, err: err)) -> err;
|
connected: extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, err: err)) -> err;
|
||||||
pub fn tcp_write(pcb: *mut tcp_pcb, dataptr: *const c_void, len: u16, apiflags: u8) -> err;
|
pub fn tcp_write(pcb: *mut tcp_pcb, dataptr: *const c_void, len: u16, apiflags: u8) -> err;
|
||||||
pub fn tcp_sent(pcb: *mut tcp_pcb,
|
pub fn tcp_sent(pcb: *mut tcp_pcb,
|
||||||
sent: extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, len: u16) -> err);
|
sent: Option<extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, len: u16) -> err>);
|
||||||
pub fn tcp_recv(pcb: *mut tcp_pcb,
|
pub fn tcp_recv(pcb: *mut tcp_pcb,
|
||||||
recv: extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, p: *mut pbuf,
|
recv: Option<extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, p: *mut pbuf,
|
||||||
err: err) -> err);
|
err: err) -> err>);
|
||||||
pub fn tcp_recved(pcb: *mut tcp_pcb, len: u16);
|
pub fn tcp_recved(pcb: *mut tcp_pcb, len: u16);
|
||||||
pub fn tcp_poll(pcb: *mut tcp_pcb,
|
pub fn tcp_poll(pcb: *mut tcp_pcb,
|
||||||
poll: extern fn(arg: *mut c_void, tcb: *mut tcp_pcb),
|
poll: Option<extern fn(arg: *mut c_void, tcb: *mut tcp_pcb)>,
|
||||||
interval: u8);
|
interval: u8);
|
||||||
pub fn tcp_shutdown(pcb: *mut tcp_pcb, shut_rx: c_int, shut_tx: c_int) -> err;
|
pub fn tcp_shutdown(pcb: *mut tcp_pcb, shut_rx: c_int, shut_tx: c_int) -> err;
|
||||||
pub fn tcp_close(pcb: *mut tcp_pcb) -> err;
|
pub fn tcp_close(pcb: *mut tcp_pcb) -> err;
|
||||||
pub fn tcp_abort(pcb: *mut tcp_pcb);
|
pub fn tcp_abort(pcb: *mut tcp_pcb);
|
||||||
pub fn tcp_err(pcb: *mut tcp_pcb,
|
pub fn tcp_err(pcb: *mut tcp_pcb,
|
||||||
err: extern fn(arg: *mut c_void, err: err));
|
err: Option<extern fn(arg: *mut c_void, err: err)>);
|
||||||
|
|
||||||
// nonstandard
|
// nonstandard
|
||||||
pub fn tcp_sndbuf_(pcb: *mut tcp_pcb) -> u16;
|
pub fn tcp_sndbuf_(pcb: *mut tcp_pcb) -> u16;
|
||||||
|
@ -154,7 +154,7 @@ extern {
|
||||||
pub fn udp_send(pcb: *mut udp_pcb, p: *mut pbuf) -> err;
|
pub fn udp_send(pcb: *mut udp_pcb, p: *mut pbuf) -> err;
|
||||||
pub fn udp_sendto(pcb: *mut udp_pcb, p: *mut pbuf, ipaddr: *mut ip_addr, port: u16) -> err;
|
pub fn udp_sendto(pcb: *mut udp_pcb, p: *mut pbuf, ipaddr: *mut ip_addr, port: u16) -> err;
|
||||||
pub fn udp_recv(pcb: *mut udp_pcb,
|
pub fn udp_recv(pcb: *mut udp_pcb,
|
||||||
recv: extern fn(arg: *mut c_void, upcb: *mut udp_pcb, p: *mut pbuf,
|
recv: Option<extern fn(arg: *mut c_void, upcb: *mut udp_pcb, p: *mut pbuf,
|
||||||
addr: *mut ip_addr, port: u16),
|
addr: *mut ip_addr, port: u16)>,
|
||||||
recv_arg: *mut c_void);
|
recv_arg: *mut c_void);
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,12 +279,12 @@ impl UdpSocket {
|
||||||
recv_buffer: LinkedList::new()
|
recv_buffer: LinkedList::new()
|
||||||
}));
|
}));
|
||||||
let arg = &mut *state as *mut RefCell<UdpSocketState> as *mut _;
|
let arg = &mut *state as *mut RefCell<UdpSocketState> as *mut _;
|
||||||
lwip_sys::udp_recv(raw, recv, arg);
|
lwip_sys::udp_recv(raw, Some(recv), arg);
|
||||||
Ok(UdpSocket { raw: raw, state: state })
|
Ok(UdpSocket { raw: raw, state: state })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn state(&self) -> *const RefCell<UdpSocketState> {
|
pub fn state(&self) -> &RefCell<UdpSocketState> {
|
||||||
&*self.state
|
&*self.state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,12 +376,12 @@ impl TcpListener {
|
||||||
}));
|
}));
|
||||||
let arg = &mut *state as *mut RefCell<TcpListenerState> as *mut _;
|
let arg = &mut *state as *mut RefCell<TcpListenerState> as *mut _;
|
||||||
lwip_sys::tcp_arg(raw2, arg);
|
lwip_sys::tcp_arg(raw2, arg);
|
||||||
lwip_sys::tcp_accept(raw2, accept);
|
lwip_sys::tcp_accept(raw2, Some(accept));
|
||||||
Ok(TcpListener { raw: raw2, state: state })
|
Ok(TcpListener { raw: raw2, state: state })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn state(&self) -> *const RefCell<TcpListenerState> {
|
pub fn state(&self) -> &RefCell<TcpListenerState> {
|
||||||
&*self.state
|
&*self.state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,14 +467,14 @@ impl TcpStream {
|
||||||
}));
|
}));
|
||||||
let arg = &mut *state as *mut RefCell<TcpStreamState> as *mut _;
|
let arg = &mut *state as *mut RefCell<TcpStreamState> as *mut _;
|
||||||
lwip_sys::tcp_arg(raw, arg);
|
lwip_sys::tcp_arg(raw, arg);
|
||||||
lwip_sys::tcp_recv(raw, recv);
|
lwip_sys::tcp_recv(raw, Some(recv));
|
||||||
lwip_sys::tcp_sent(raw, sent);
|
lwip_sys::tcp_sent(raw, Some(sent));
|
||||||
lwip_sys::tcp_err(raw, err);
|
lwip_sys::tcp_err(raw, Some(err));
|
||||||
TcpStream { raw: raw, state: state }
|
TcpStream { raw: raw, state: state }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn state(&self) -> *const RefCell<TcpStreamState> {
|
pub fn state(&self) -> &RefCell<TcpStreamState> {
|
||||||
&*self.state
|
&*self.state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,6 +536,11 @@ impl TcpStream {
|
||||||
impl Drop for TcpStream {
|
impl Drop for TcpStream {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
// lwip *will* try to call back after tcp_close
|
||||||
|
lwip_sys::tcp_recv(self.raw, None);
|
||||||
|
lwip_sys::tcp_sent(self.raw, None);
|
||||||
|
lwip_sys::tcp_err(self.raw, None);
|
||||||
|
|
||||||
// tcp_close can fail here, but in drop() we don't care
|
// tcp_close can fail here, but in drop() we don't care
|
||||||
let _ = lwip_sys::tcp_close(self.raw);
|
let _ = lwip_sys::tcp_close(self.raw);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
use core::ptr;
|
||||||
|
use board::csr::kernel_cpu;
|
||||||
|
use mailbox;
|
||||||
|
|
||||||
|
const KERNELCPU_EXEC_ADDRESS: usize = 0x42000000;
|
||||||
|
const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x42020000;
|
||||||
|
const KERNELCPU_LAST_ADDRESS: usize = (0x4fffffff - 1024*1024);
|
||||||
|
const KSUPPORT_HEADER_SIZE: usize = 0x80;
|
||||||
|
|
||||||
|
pub unsafe fn start() {
|
||||||
|
if kernel_cpu::reset_read() == 0 {
|
||||||
|
panic!("attempted to start kernel CPU when it is already running")
|
||||||
|
}
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
extern {
|
||||||
|
static _binary_ksupport_elf_start: ();
|
||||||
|
static _binary_ksupport_elf_end: ();
|
||||||
|
}
|
||||||
|
let ksupport_start = &_binary_ksupport_elf_start as *const _ as usize;
|
||||||
|
let ksupport_end = &_binary_ksupport_elf_end as *const _ as usize;
|
||||||
|
ptr::copy_nonoverlapping(ksupport_start as *const u8,
|
||||||
|
(KERNELCPU_EXEC_ADDRESS - KSUPPORT_HEADER_SIZE) as *mut u8,
|
||||||
|
ksupport_end - ksupport_start);
|
||||||
|
|
||||||
|
kernel_cpu::reset_write(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop() {
|
||||||
|
unsafe { kernel_cpu::reset_write(1) }
|
||||||
|
mailbox::acknowledge();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate(ptr: usize) -> bool {
|
||||||
|
ptr >= KERNELCPU_EXEC_ADDRESS && ptr <= KERNELCPU_LAST_ADDRESS
|
||||||
|
}
|
|
@ -0,0 +1,323 @@
|
||||||
|
use std::io;
|
||||||
|
use mailbox;
|
||||||
|
use kernel;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Exception<'a> {
|
||||||
|
pub name: &'a str,
|
||||||
|
pub file: &'a str,
|
||||||
|
pub line: u32,
|
||||||
|
pub column: u32,
|
||||||
|
pub function: &'a str,
|
||||||
|
pub message: &'a str,
|
||||||
|
pub param: [u64; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::c::BacktraceItem;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Message<'a> {
|
||||||
|
LoadRequest(&'a [u8]),
|
||||||
|
LoadReply { error: Option<&'a str> },
|
||||||
|
|
||||||
|
NowInitRequest,
|
||||||
|
NowInitReply(u64),
|
||||||
|
NowSave(u64),
|
||||||
|
|
||||||
|
RunFinished,
|
||||||
|
RunException {
|
||||||
|
exception: Exception<'a>,
|
||||||
|
backtrace: &'a [BacktraceItem]
|
||||||
|
},
|
||||||
|
|
||||||
|
WatchdogSetRequest { ms: u64 },
|
||||||
|
WatchdogSetReply { id: usize },
|
||||||
|
WatchdogClear { id: usize },
|
||||||
|
|
||||||
|
RpcSend {
|
||||||
|
service: u32,
|
||||||
|
tag: &'a [u8],
|
||||||
|
data: *const *const ()
|
||||||
|
},
|
||||||
|
RpcRecvRequest {
|
||||||
|
slot: *mut ()
|
||||||
|
},
|
||||||
|
RpcRecvReply {
|
||||||
|
alloc_size: usize,
|
||||||
|
exception: Option<Exception<'a>>
|
||||||
|
},
|
||||||
|
|
||||||
|
CacheGetRequest { key: &'a str },
|
||||||
|
CacheGetReply { value: &'static [u32] },
|
||||||
|
CachePutRequest { key: &'a str, value: &'static [u32] },
|
||||||
|
CachePutReply { succeeded: bool },
|
||||||
|
|
||||||
|
Log(&'a str)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::Message::*;
|
||||||
|
|
||||||
|
impl<'a> Message<'a> {
|
||||||
|
fn into_lower<R, F: FnOnce(*const ()) -> R>(self, f: F) -> R {
|
||||||
|
match self {
|
||||||
|
Message::LoadRequest(library) => {
|
||||||
|
let msg = c::LoadRequest {
|
||||||
|
ty: c::Type::LoadRequest,
|
||||||
|
library: library.as_ptr() as *const _
|
||||||
|
};
|
||||||
|
f(&msg as *const _ as *const _)
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::NowInitReply(now) => {
|
||||||
|
let msg = c::NowInitReply {
|
||||||
|
ty: c::Type::NowInitReply,
|
||||||
|
now: now
|
||||||
|
};
|
||||||
|
f(&msg as *const _ as *const _)
|
||||||
|
}
|
||||||
|
|
||||||
|
other => panic!("Message::into_lower: {:?} unimplemented", other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_lower(ptr: *const ()) -> Self {
|
||||||
|
let msg = ptr as *const c::Message;
|
||||||
|
match (*msg).ty {
|
||||||
|
c::Type::LoadReply => {
|
||||||
|
let msg = ptr as *const c::LoadReply;
|
||||||
|
let error = if (*msg).error.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(c::from_c_str((*msg).error))
|
||||||
|
};
|
||||||
|
Message::LoadReply { error: error }
|
||||||
|
}
|
||||||
|
|
||||||
|
c::Type::NowInitRequest => Message::NowInitRequest,
|
||||||
|
c::Type::NowSave => {
|
||||||
|
let msg = ptr as *const c::NowSave;
|
||||||
|
Message::NowSave((*msg).now)
|
||||||
|
}
|
||||||
|
|
||||||
|
c::Type::RunFinished => Message::RunFinished,
|
||||||
|
|
||||||
|
c::Type::Log => {
|
||||||
|
let msg = ptr as *const c::Log;
|
||||||
|
Message::Log(c::from_c_str_len((*msg).buf, (*msg).len))
|
||||||
|
}
|
||||||
|
|
||||||
|
ref other => panic!("Message::from_lower: {:?} unimplemented", other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_and_wait(self, waiter: ::sched::Waiter) -> io::Result<()> {
|
||||||
|
self.into_lower(|ptr| {
|
||||||
|
unsafe { mailbox::send(ptr as usize) }
|
||||||
|
waiter.until(mailbox::acknowledged)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait_and_receive<R, F>(waiter: ::sched::Waiter, f: F) -> io::Result<R>
|
||||||
|
where F: FnOnce(Message<'a>) -> io::Result<R> {
|
||||||
|
try!(waiter.until(|| mailbox::receive() != 0));
|
||||||
|
if !kernel::validate(mailbox::receive()) {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid kernel CPU pointer"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let msg = unsafe { Self::from_lower(mailbox::receive() as *const ()) };
|
||||||
|
Ok(try!(f(msg)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn acknowledge() {
|
||||||
|
unsafe { mailbox::acknowledge() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Low-level representation, compatible with the C code in ksupport
|
||||||
|
mod c {
|
||||||
|
use libc::{c_void, c_int, c_char, size_t};
|
||||||
|
|
||||||
|
#[repr(u32)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Type {
|
||||||
|
LoadRequest,
|
||||||
|
LoadReply,
|
||||||
|
NowInitRequest,
|
||||||
|
NowInitReply,
|
||||||
|
NowSave,
|
||||||
|
RunFinished,
|
||||||
|
RunException,
|
||||||
|
WatchdogSetRequest,
|
||||||
|
WatchdogSetReply,
|
||||||
|
WatchdogClear,
|
||||||
|
RpcSend,
|
||||||
|
RpcRecvRequest,
|
||||||
|
RpcRecvReply,
|
||||||
|
RpcBatch,
|
||||||
|
CacheGetRequest,
|
||||||
|
CacheGetReply,
|
||||||
|
CachePutRequest,
|
||||||
|
CachePutReply,
|
||||||
|
Log,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Message {
|
||||||
|
pub ty: Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// kernel messages
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LoadRequest {
|
||||||
|
pub ty: Type,
|
||||||
|
pub library: *const c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LoadReply {
|
||||||
|
pub ty: Type,
|
||||||
|
pub error: *const c_char
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NowInitReply {
|
||||||
|
pub ty: Type,
|
||||||
|
pub now: u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NowSave {
|
||||||
|
pub ty: Type,
|
||||||
|
pub now: u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RunException {
|
||||||
|
pub ty: Type,
|
||||||
|
pub exception: *const Exception,
|
||||||
|
pub backtrace: *const BacktraceItem,
|
||||||
|
pub backtrace_size: size_t
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WatchdogSetRequest {
|
||||||
|
pub ty: Type,
|
||||||
|
pub ms: c_int
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WatchdogSetReply {
|
||||||
|
pub ty: Type,
|
||||||
|
pub id: c_int
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WatchdogClear {
|
||||||
|
pub ty: Type,
|
||||||
|
pub id: c_int
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RpcSend {
|
||||||
|
pub ty: Type,
|
||||||
|
pub service: c_int,
|
||||||
|
pub tag: *const c_char,
|
||||||
|
pub data: *const *const c_void
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RpcRecvRequest {
|
||||||
|
pub ty: Type,
|
||||||
|
pub slot: *mut c_void
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RpcRecvReply {
|
||||||
|
pub ty: Type,
|
||||||
|
pub alloc_size: c_int,
|
||||||
|
pub exception: *const Exception
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CacheGetRequest {
|
||||||
|
pub ty: Type,
|
||||||
|
pub key: *const c_char
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CacheGetReply {
|
||||||
|
pub ty: Type,
|
||||||
|
pub length: size_t,
|
||||||
|
pub elements: *const u32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CachePutRequest {
|
||||||
|
pub ty: Type,
|
||||||
|
pub key: *const c_char,
|
||||||
|
pub length: size_t,
|
||||||
|
pub elements: *const u32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CachePutReply {
|
||||||
|
pub ty: Type,
|
||||||
|
pub succeeded: c_int
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Log {
|
||||||
|
pub ty: Type,
|
||||||
|
pub buf: *const c_char,
|
||||||
|
pub len: size_t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supplementary structures
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Exception {
|
||||||
|
pub name: *const c_char, // or typeinfo
|
||||||
|
pub file: *const c_char,
|
||||||
|
pub line: u32,
|
||||||
|
pub column: u32,
|
||||||
|
pub function: *const c_char,
|
||||||
|
pub message: *const c_char,
|
||||||
|
pub param: [u64; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BacktraceItem {
|
||||||
|
pub function: usize,
|
||||||
|
pub offset: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn from_c_str_len<'a>(ptr: *const c_char, len: size_t) -> &'a str {
|
||||||
|
use core::{str, slice};
|
||||||
|
str::from_utf8_unchecked(slice::from_raw_parts(ptr as *const u8, len))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn from_c_str<'a>(ptr: *const c_char) -> &'a str {
|
||||||
|
extern { fn strlen(cs: *const c_char) -> size_t; }
|
||||||
|
from_c_str_len(ptr, strlen(ptr))
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,10 @@ mod mailbox;
|
||||||
|
|
||||||
mod logger;
|
mod logger;
|
||||||
|
|
||||||
|
mod kernel_proto;
|
||||||
mod session_proto;
|
mod session_proto;
|
||||||
|
|
||||||
|
mod kernel;
|
||||||
mod session;
|
mod session;
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
|
@ -42,9 +45,10 @@ pub unsafe extern fn rust_main() {
|
||||||
network_init();
|
network_init();
|
||||||
|
|
||||||
let mut scheduler = sched::Scheduler::new();
|
let mut scheduler = sched::Scheduler::new();
|
||||||
scheduler.spawn(4096, move |waiter| {
|
scheduler.spawn(8192, move |waiter| {
|
||||||
session::handler(waiter, logger)
|
session::handler(waiter, logger)
|
||||||
});
|
});
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
lwip_service();
|
lwip_service();
|
||||||
scheduler.run()
|
scheduler.run()
|
||||||
|
|
|
@ -48,9 +48,9 @@ impl Log for BufferLogger {
|
||||||
if self.enabled(record.metadata()) {
|
if self.enabled(record.metadata()) {
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
writeln!(self.buffer.borrow_mut(), "{:>5}({}): {}",
|
writeln!(self.buffer.borrow_mut(), "{:>5}({}): {}",
|
||||||
record.level(), record.location().module_path(), record.args()).unwrap();
|
record.level(), record.target(), record.args()).unwrap();
|
||||||
println!("{:>5}({}): {}",
|
println!("{:>5}({}): {}",
|
||||||
record.level(), record.location().module_path(), record.args());
|
record.level(), record.target(), record.args());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
use core::ptr::{read_volatile, write_volatile};
|
use core::ptr::{read_volatile, write_volatile};
|
||||||
use board;
|
use board;
|
||||||
|
|
||||||
const MAILBOX: *mut u32 = board::mem::MAILBOX_BASE as *mut u32;
|
const MAILBOX: *mut usize = board::mem::MAILBOX_BASE as *mut usize;
|
||||||
static mut last: u32 = 0;
|
static mut last: usize = 0;
|
||||||
|
|
||||||
pub fn send(data: u32) {
|
pub unsafe fn send(data: usize) {
|
||||||
unsafe {
|
last = data;
|
||||||
last = data;
|
write_volatile(MAILBOX, data)
|
||||||
write_volatile(MAILBOX, data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn acknowledged() -> bool {
|
pub fn acknowledged() -> bool {
|
||||||
|
@ -18,12 +16,7 @@ pub fn acknowledged() -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_and_wait(data: u32) {
|
pub fn receive() -> usize {
|
||||||
send(data);
|
|
||||||
while !acknowledged() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn receive() -> u32 {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = read_volatile(MAILBOX);
|
let data = read_volatile(MAILBOX);
|
||||||
if data == last {
|
if data == last {
|
||||||
|
@ -37,15 +30,6 @@ pub fn receive() -> u32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait_and_receive() -> u32 {
|
|
||||||
loop {
|
|
||||||
let data = receive();
|
|
||||||
if data != 0 {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn acknowledge() {
|
pub fn acknowledge() {
|
||||||
unsafe { write_volatile(MAILBOX, 0) }
|
unsafe { write_volatile(MAILBOX, 0) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,8 +104,8 @@ impl Scheduler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum WaitEvent {
|
enum WaitEvent {
|
||||||
|
Completion(*const (Fn() -> bool + 'static)),
|
||||||
UdpReadable(*const RefCell<lwip::UdpSocketState>),
|
UdpReadable(*const RefCell<lwip::UdpSocketState>),
|
||||||
TcpAcceptable(*const RefCell<lwip::TcpListenerState>),
|
TcpAcceptable(*const RefCell<lwip::TcpListenerState>),
|
||||||
TcpWriteable(*const RefCell<lwip::TcpStreamState>),
|
TcpWriteable(*const RefCell<lwip::TcpStreamState>),
|
||||||
|
@ -115,6 +115,8 @@ enum WaitEvent {
|
||||||
impl WaitEvent {
|
impl WaitEvent {
|
||||||
fn completed(&self) -> bool {
|
fn completed(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
|
WaitEvent::Completion(f) =>
|
||||||
|
unsafe { (*f)() },
|
||||||
WaitEvent::UdpReadable(state) =>
|
WaitEvent::UdpReadable(state) =>
|
||||||
unsafe { (*state).borrow().readable() },
|
unsafe { (*state).borrow().readable() },
|
||||||
WaitEvent::TcpAcceptable(state) =>
|
WaitEvent::TcpAcceptable(state) =>
|
||||||
|
@ -127,12 +129,27 @@ impl WaitEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// *const DST doesn't have impl Debug
|
||||||
|
impl ::core::fmt::Debug for WaitEvent {
|
||||||
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) ->
|
||||||
|
::core::result::Result<(), ::core::fmt::Error> {
|
||||||
|
write!(f, "WaitEvent...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl Send for WaitEvent {}
|
unsafe impl Send for WaitEvent {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Waiter<'a>(&'a Yielder<WaitResult, WaitRequest, OwnedStack>);
|
pub struct Waiter<'a>(&'a Yielder<WaitResult, WaitRequest, OwnedStack>);
|
||||||
|
|
||||||
impl<'a> Waiter<'a> {
|
impl<'a> Waiter<'a> {
|
||||||
|
pub fn relinquish(&self) {
|
||||||
|
self.0.suspend(WaitRequest {
|
||||||
|
timeout: None,
|
||||||
|
event: None
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sleep(&self, duration: Duration) -> Result<()> {
|
pub fn sleep(&self, duration: Duration) -> Result<()> {
|
||||||
let request = WaitRequest {
|
let request = WaitRequest {
|
||||||
timeout: Some(Instant::now() + duration),
|
timeout: Some(Instant::now() + duration),
|
||||||
|
@ -154,6 +171,13 @@ impl<'a> Waiter<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn until<F: Fn() -> bool + 'static>(&self, f: F) -> Result<()> {
|
||||||
|
self.suspend(WaitRequest {
|
||||||
|
timeout: None,
|
||||||
|
event: Some(WaitEvent::Completion(&f as *const _))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn udp_readable(&self, socket: &lwip::UdpSocket) -> Result<()> {
|
pub fn udp_readable(&self, socket: &lwip::UdpSocket) -> Result<()> {
|
||||||
self.suspend(WaitRequest {
|
self.suspend(WaitRequest {
|
||||||
timeout: None,
|
timeout: None,
|
||||||
|
@ -239,6 +263,10 @@ impl<'a> UdpSocket<'a> {
|
||||||
(&mut buf[..len]).copy_from_slice(&pbuf.as_slice()[..len]);
|
(&mut buf[..len]).copy_from_slice(&pbuf.as_slice()[..len]);
|
||||||
Ok(len)
|
Ok(len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn readable(&self) -> bool {
|
||||||
|
self.lower.state().borrow().readable()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -265,6 +293,10 @@ impl<'a> TcpListener<'a> {
|
||||||
buffer: None
|
buffer: None
|
||||||
}, addr))
|
}, addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn acceptable(&self) -> bool {
|
||||||
|
self.lower.state().borrow().acceptable()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::lwip::Shutdown;
|
pub use self::lwip::Shutdown;
|
||||||
|
@ -280,6 +312,14 @@ impl<'a> TcpStream<'a> {
|
||||||
pub fn shutdown(&self, how: Shutdown) -> Result<()> {
|
pub fn shutdown(&self, how: Shutdown) -> Result<()> {
|
||||||
Ok(try!(self.lower.shutdown(how)))
|
Ok(try!(self.lower.shutdown(how)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn readable(&self) -> bool {
|
||||||
|
self.buffer.is_some() || self.lower.state().borrow().readable()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn writeable(&self) -> bool {
|
||||||
|
self.lower.state().borrow().writeable()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Read for TcpStream<'a> {
|
impl<'a> Read for TcpStream<'a> {
|
||||||
|
|
|
@ -1,12 +1,23 @@
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::io::{self, Read, ErrorKind};
|
use std::io::{self, Read};
|
||||||
use {config, rtio_crg};
|
use {config, rtio_crg, clock, mailbox, kernel};
|
||||||
use logger::BufferLogger;
|
use logger::BufferLogger;
|
||||||
use sched::{Waiter, TcpListener, TcpStream, SocketAddr, IP_ANY};
|
use sched::{Waiter, TcpListener, TcpStream, SocketAddr, IP_ANY};
|
||||||
use session_proto::*;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
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"))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum KernelState {
|
enum KernelState {
|
||||||
Absent,
|
Absent,
|
||||||
Loaded,
|
Loaded,
|
||||||
|
@ -17,19 +28,16 @@ enum KernelState {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
kernel_state: KernelState,
|
kernel_state: KernelState,
|
||||||
}
|
watchdog_set: clock::WatchdogSet,
|
||||||
|
now: u64
|
||||||
extern {
|
|
||||||
fn kloader_stop();
|
|
||||||
fn watchdog_init();
|
|
||||||
fn kloader_start_idle_kernel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Session {
|
impl Session {
|
||||||
pub fn new() -> Session {
|
pub fn new() -> Session {
|
||||||
unsafe { kloader_stop(); }
|
|
||||||
Session {
|
Session {
|
||||||
kernel_state: KernelState::Absent
|
kernel_state: KernelState::Absent,
|
||||||
|
watchdog_set: clock::WatchdogSet::new(),
|
||||||
|
now: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,16 +49,6 @@ impl Session {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Session {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
kloader_stop();
|
|
||||||
watchdog_init();
|
|
||||||
kloader_start_idle_kernel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_magic(stream: &mut TcpStream) -> io::Result<()> {
|
fn check_magic(stream: &mut TcpStream) -> io::Result<()> {
|
||||||
const MAGIC: &'static [u8] = b"ARTIQ coredev\n";
|
const MAGIC: &'static [u8] = b"ARTIQ coredev\n";
|
||||||
|
|
||||||
|
@ -63,89 +61,203 @@ fn check_magic(stream: &mut TcpStream) -> io::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_request(stream: &mut TcpStream,
|
fn host_read(stream: &mut TcpStream) -> io::Result<host::Request> {
|
||||||
logger: &BufferLogger,
|
let request = try!(host::Request::read_from(stream));
|
||||||
session: &mut Session) -> io::Result<()> {
|
match &request {
|
||||||
fn read_request(stream: &mut TcpStream) -> io::Result<Request> {
|
&host::Request::LoadLibrary(_) => trace!("comm<-host LoadLibrary(...)"),
|
||||||
let request = try!(Request::read_from(stream));
|
_ => trace!("comm<-host {:?}", request)
|
||||||
match &request {
|
|
||||||
&Request::LoadLibrary(_) => trace!("comm<-host LoadLibrary(...)"),
|
|
||||||
_ => trace!("comm<-host {:?}", request)
|
|
||||||
}
|
|
||||||
Ok(request)
|
|
||||||
}
|
}
|
||||||
|
Ok(request)
|
||||||
|
}
|
||||||
|
|
||||||
fn write_reply(stream: &mut TcpStream, reply: Reply) -> io::Result<()> {
|
fn host_write(stream: &mut TcpStream, reply: host::Reply) -> io::Result<()> {
|
||||||
trace!("comm->host {:?}", reply);
|
trace!("comm->host {:?}", reply);
|
||||||
reply.write_to(stream)
|
reply.write_to(stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kern_send<'a>(waiter: Waiter, request: kern::Message<'a>) -> io::Result<()> {
|
||||||
|
match &request {
|
||||||
|
&kern::LoadRequest(_) => trace!("comm->kern LoadRequest(...)"),
|
||||||
|
_ => trace!("comm->kern {:?}", request)
|
||||||
}
|
}
|
||||||
|
request.send_and_wait(waiter)
|
||||||
|
}
|
||||||
|
|
||||||
match try!(read_request(stream)) {
|
fn kern_recv<R, F>(waiter: Waiter, f: F) -> io::Result<R>
|
||||||
Request::Ident =>
|
where F: FnOnce(kern::Message) -> io::Result<R> {
|
||||||
write_reply(stream, Reply::Ident(::board::ident(&mut [0; 64]))),
|
kern::Message::wait_and_receive(waiter, |reply| {
|
||||||
|
trace!("comm<-kern {:?}", reply);
|
||||||
|
f(reply)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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]))),
|
||||||
|
|
||||||
// artiq_corelog
|
// artiq_corelog
|
||||||
Request::Log => {
|
host::Request::Log => {
|
||||||
// Logging the packet with the log is inadvisable
|
// Logging the packet with the log is inadvisable
|
||||||
trace!("comm->host Log(...)");
|
trace!("comm->host Log(...)");
|
||||||
logger.extract(move |log| {
|
logger.extract(move |log| {
|
||||||
Reply::Log(log).write_to(stream)
|
host::Reply::Log(log).write_to(stream)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Request::LogClear => {
|
host::Request::LogClear => {
|
||||||
logger.clear();
|
logger.clear();
|
||||||
write_reply(stream, Reply::Log(""))
|
host_write(stream, host::Reply::Log(""))
|
||||||
}
|
}
|
||||||
|
|
||||||
// artiq_coreconfig
|
// artiq_coreconfig
|
||||||
Request::FlashRead { ref key } => {
|
host::Request::FlashRead { ref key } => {
|
||||||
let value = config::read_to_end(key);
|
let value = config::read_to_end(key);
|
||||||
write_reply(stream, Reply::FlashRead(&value))
|
host_write(stream, host::Reply::FlashRead(&value))
|
||||||
}
|
}
|
||||||
|
|
||||||
Request::FlashWrite { ref key, ref value } => {
|
host::Request::FlashWrite { ref key, ref value } => {
|
||||||
match config::write(key, value) {
|
match config::write(key, value) {
|
||||||
Ok(_) => write_reply(stream, Reply::FlashOk),
|
Ok(_) => host_write(stream, host::Reply::FlashOk),
|
||||||
Err(_) => write_reply(stream, Reply::FlashError)
|
Err(_) => host_write(stream, host::Reply::FlashError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Request::FlashRemove { ref key } => {
|
host::Request::FlashRemove { ref key } => {
|
||||||
config::remove(key);
|
config::remove(key);
|
||||||
write_reply(stream, Reply::FlashOk)
|
host_write(stream, host::Reply::FlashOk)
|
||||||
}
|
}
|
||||||
|
|
||||||
Request::FlashErase => {
|
host::Request::FlashErase => {
|
||||||
config::erase();
|
config::erase();
|
||||||
write_reply(stream, Reply::FlashOk)
|
host_write(stream, host::Reply::FlashOk)
|
||||||
}
|
}
|
||||||
|
|
||||||
// artiq_run/artiq_master
|
// artiq_run/artiq_master
|
||||||
Request::SwitchClock(clk) => {
|
host::Request::SwitchClock(clk) => {
|
||||||
if session.running() {
|
if session.running() {
|
||||||
error!("attempted to switch RTIO clock while kernel was running");
|
error!("attempted to switch RTIO clock while a kernel was running");
|
||||||
write_reply(stream, Reply::ClockSwitchFailed)
|
return host_write(stream, host::Reply::ClockSwitchFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rtio_crg::switch_clock(clk) {
|
||||||
|
host_write(stream, host::Reply::ClockSwitchCompleted)
|
||||||
} else {
|
} else {
|
||||||
if rtio_crg::switch_clock(clk) {
|
host_write(stream, host::Reply::ClockSwitchFailed)
|
||||||
write_reply(stream, Reply::ClockSwitchCompleted)
|
|
||||||
} else {
|
|
||||||
write_reply(stream, Reply::ClockSwitchFailed)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unreachable!()
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
session.kernel_state = KernelState::Running;
|
||||||
|
kern_acknowledge()
|
||||||
|
}
|
||||||
|
|
||||||
|
request => unexpected!("unexpected {:?}", request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_requests(stream: &mut TcpStream,
|
fn kern_handle(waiter: Waiter,
|
||||||
logger: &BufferLogger) -> io::Result<()> {
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
request => unexpected!("unexpected {:?}", request)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle(waiter: Waiter,
|
||||||
|
stream: &mut TcpStream,
|
||||||
|
logger: &BufferLogger) -> io::Result<()> {
|
||||||
try!(check_magic(stream));
|
try!(check_magic(stream));
|
||||||
|
|
||||||
let mut session = Session::new();
|
let mut session = Session::new();
|
||||||
loop {
|
loop {
|
||||||
try!(handle_request(stream, logger, &mut session))
|
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));
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "watchdog expired"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rtio_crg::check() {
|
||||||
|
try!(host_write(stream, host::Reply::ClockFailure));
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "RTIO clock failure"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waiter.relinquish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,13 +271,13 @@ pub fn handler(waiter: Waiter,
|
||||||
let (mut stream, addr) = listener.accept().unwrap();
|
let (mut stream, addr) = listener.accept().unwrap();
|
||||||
info!("new connection from {:?}", addr);
|
info!("new connection from {:?}", addr);
|
||||||
|
|
||||||
match handle_requests(&mut stream, logger) {
|
match handle(waiter, &mut stream, logger) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if err.kind() == ErrorKind::UnexpectedEof {
|
if err.kind() == io::ErrorKind::UnexpectedEof {
|
||||||
info!("connection closed");
|
info!("connection closed");
|
||||||
} else {
|
} else {
|
||||||
error!("cannot handle network request: {:?}", err);
|
error!("session aborted: {:?}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ all: runtime.bin runtime.fbi
|
||||||
%.fbi: %.bin
|
%.fbi: %.bin
|
||||||
@echo " MSCIMG " $@ && $(PYTHON) -m misoc.tools.mkmscimg -f -o $@ $<
|
@echo " MSCIMG " $@ && $(PYTHON) -m misoc.tools.mkmscimg -f -o $@ $<
|
||||||
|
|
||||||
runtime.elf: $(OBJECTS) libartiq_rust.a
|
runtime.elf: $(OBJECTS) libruntime.a
|
||||||
$(LD) $(LDFLAGS) \
|
$(LD) $(LDFLAGS) \
|
||||||
--gc-sections \
|
--gc-sections \
|
||||||
-T $(RUNTIME_DIRECTORY)/runtime.ld \
|
-T $(RUNTIME_DIRECTORY)/runtime.ld \
|
||||||
|
@ -40,7 +40,7 @@ runtime.elf: $(OBJECTS) libartiq_rust.a
|
||||||
-L../liballoc \
|
-L../liballoc \
|
||||||
-L../liblwip \
|
-L../liblwip \
|
||||||
-Lcargo/or1k-unknown-none/debug/ \
|
-Lcargo/or1k-unknown-none/debug/ \
|
||||||
-lartiq_rust -lbase -lm -lcompiler-rt -lalloc -llwip
|
-lruntime -lbase -lm -lcompiler-rt -lalloc -llwip
|
||||||
@chmod -x $@
|
@chmod -x $@
|
||||||
|
|
||||||
ksupport.elf: $(OBJECTS_KSUPPORT)
|
ksupport.elf: $(OBJECTS_KSUPPORT)
|
||||||
|
@ -60,7 +60,7 @@ ksupport.elf: $(OBJECTS_KSUPPORT)
|
||||||
ksupport_data.o: ksupport.elf
|
ksupport_data.o: ksupport.elf
|
||||||
$(LD) -r -b binary -o $@ $<
|
$(LD) -r -b binary -o $@ $<
|
||||||
|
|
||||||
libartiq_rust.a:
|
libruntime.a:
|
||||||
CARGO_TARGET_DIR="./cargo" \
|
CARGO_TARGET_DIR="./cargo" \
|
||||||
cargo rustc --verbose \
|
cargo rustc --verbose \
|
||||||
--manifest-path $(RUNTIME_DIRECTORY)/../runtime.rs/Cargo.toml \
|
--manifest-path $(RUNTIME_DIRECTORY)/../runtime.rs/Cargo.toml \
|
||||||
|
|
|
@ -167,7 +167,7 @@ void kloader_service_essential_kmsg(void)
|
||||||
case MESSAGE_TYPE_LOG: {
|
case MESSAGE_TYPE_LOG: {
|
||||||
struct msg_log *msg = (struct msg_log *)umsg;
|
struct msg_log *msg = (struct msg_log *)umsg;
|
||||||
|
|
||||||
core_log_va(msg->fmt, msg->args);
|
core_log("%s", msg->buf);
|
||||||
mailbox_acknowledge();
|
mailbox_acknowledge();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue