forked from M-Labs/artiq
runtime: implement prototype background RPCs.
This commit is contained in:
parent
c656a53532
commit
2ac85cd40f
|
@ -7,7 +7,7 @@ from misoc.integration.soc_core import mem_decoder
|
||||||
|
|
||||||
class KernelCPU(Module):
|
class KernelCPU(Module):
|
||||||
def __init__(self, platform,
|
def __init__(self, platform,
|
||||||
exec_address=0x40400000,
|
exec_address=0x40800000,
|
||||||
main_mem_origin=0x40000000,
|
main_mem_origin=0x40000000,
|
||||||
l2_size=8192):
|
l2_size=8192):
|
||||||
self._reset = CSRStorage(reset=1)
|
self._reset = CSRStorage(reset=1)
|
||||||
|
|
|
@ -16,7 +16,7 @@ path = "src/lib.rs"
|
||||||
std_artiq = { path = "libstd_artiq" }
|
std_artiq = { path = "libstd_artiq" }
|
||||||
lwip = { path = "liblwip", default-features = false }
|
lwip = { path = "liblwip", default-features = false }
|
||||||
fringe = { version = "= 1.1.0", default-features = false, features = ["alloc"] }
|
fringe = { version = "= 1.1.0", default-features = false, features = ["alloc"] }
|
||||||
log = { version = "0.3", default-features = false, features = ["max_level_debug"] }
|
log = { version = "0.3", default-features = false, features = [] }
|
||||||
log_buffer = { version = "1.0" }
|
log_buffer = { version = "1.0" }
|
||||||
byteorder = { version = "0.5", default-features = false }
|
byteorder = { version = "0.5", default-features = false }
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,26 @@
|
||||||
[root]
|
[root]
|
||||||
name = "ksupport"
|
name = "ksupport"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"std_artiq 0.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alloc_artiq"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "std_artiq"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"alloc_artiq 0.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
|
||||||
|
|
|
@ -8,6 +8,10 @@ name = "ksupport"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
crate-type = ["staticlib"]
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
std_artiq = { path = "../libstd_artiq" }
|
||||||
|
byteorder = { version = "0.5", default-features = false }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = 'unwind'
|
panic = 'unwind'
|
||||||
opt-level = 2
|
opt-level = 2
|
||||||
|
|
|
@ -91,6 +91,7 @@ static mut API: &'static [(&'static str, *const ())] = &[
|
||||||
api!(watchdog_clear = ::watchdog_clear),
|
api!(watchdog_clear = ::watchdog_clear),
|
||||||
|
|
||||||
api!(send_rpc = ::send_rpc),
|
api!(send_rpc = ::send_rpc),
|
||||||
|
api!(send_async_rpc = ::send_async_rpc),
|
||||||
api!(recv_rpc = ::recv_rpc),
|
api!(recv_rpc = ::recv_rpc),
|
||||||
|
|
||||||
api!(cache_get = ::cache_get),
|
api!(cache_get = ::cache_get),
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use core::{ptr, slice, str};
|
use core::{ptr, slice, str};
|
||||||
use core::slice::SliceExt;
|
|
||||||
use libc::{c_void, c_char, c_int, size_t};
|
use libc::{c_void, c_char, c_int, size_t};
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
|
|
@ -1,25 +1,51 @@
|
||||||
#![feature(lang_items, needs_panic_runtime, asm, libc, core_slice_ext)]
|
#![feature(lang_items, needs_panic_runtime, asm, libc, stmt_expr_attributes)]
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![needs_panic_runtime]
|
#![needs_panic_runtime]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate std_artiq as std;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
extern crate byteorder;
|
||||||
|
|
||||||
#[path = "../src/board.rs"]
|
#[path = "../src/board.rs"]
|
||||||
mod board;
|
mod board;
|
||||||
#[path = "../src/mailbox.rs"]
|
#[path = "../src/mailbox.rs"]
|
||||||
mod mailbox;
|
mod mailbox;
|
||||||
|
#[path = "../src/rpc_queue.rs"]
|
||||||
|
mod rpc_queue;
|
||||||
|
|
||||||
|
#[path = "../src/proto.rs"]
|
||||||
|
mod proto;
|
||||||
#[path = "../src/kernel_proto.rs"]
|
#[path = "../src/kernel_proto.rs"]
|
||||||
mod kernel_proto;
|
mod kernel_proto;
|
||||||
|
#[path = "../src/rpc_proto.rs"]
|
||||||
|
mod rpc_proto;
|
||||||
|
|
||||||
mod dyld;
|
mod dyld;
|
||||||
mod api;
|
mod api;
|
||||||
|
|
||||||
use core::{mem, ptr, slice, str};
|
use core::{mem, ptr, slice, str};
|
||||||
|
use std::io::Cursor;
|
||||||
use libc::{c_char, size_t};
|
use libc::{c_char, size_t};
|
||||||
use kernel_proto::*;
|
use kernel_proto::*;
|
||||||
use dyld::Library;
|
use dyld::Library;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn malloc(_size: usize) -> *mut libc::c_void {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn realloc(_ptr: *mut libc::c_void, _size: usize) -> *mut libc::c_void {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn free(_ptr: *mut libc::c_void) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn send(request: &Message) {
|
fn send(request: &Message) {
|
||||||
unsafe { mailbox::send(request as *const _ as usize) }
|
unsafe { mailbox::send(request as *const _ as usize) }
|
||||||
while !mailbox::acknowledged() {}
|
while !mailbox::acknowledged() {}
|
||||||
|
@ -81,13 +107,37 @@ extern fn send_rpc(service: u32, tag: *const u8, data: *const *const ()) {
|
||||||
let tag = unsafe { slice::from_raw_parts(tag, strlen(tag as *const c_char)) };
|
let tag = unsafe { slice::from_raw_parts(tag, strlen(tag as *const c_char)) };
|
||||||
|
|
||||||
send(&RpcSend {
|
send(&RpcSend {
|
||||||
service: service as u32,
|
async: false,
|
||||||
batch: service == 0,
|
service: service,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern fn send_async_rpc(service: u32, tag: *const u8, data: *const *const ()) {
|
||||||
|
extern { fn strlen(s: *const c_char) -> size_t; }
|
||||||
|
let tag = unsafe { slice::from_raw_parts(tag, strlen(tag as *const c_char)) };
|
||||||
|
|
||||||
|
while rpc_queue::full() {}
|
||||||
|
rpc_queue::enqueue(|mut slice| {
|
||||||
|
let length = {
|
||||||
|
let mut writer = Cursor::new(&mut slice[4..]);
|
||||||
|
try!(rpc_proto::send_args(&mut writer, service, tag, data));
|
||||||
|
writer.position()
|
||||||
|
};
|
||||||
|
proto::write_u32(&mut slice, length as u32)
|
||||||
|
}).unwrap_or_else(|err| {
|
||||||
|
assert!(err.kind() == std::io::ErrorKind::UnexpectedEof);
|
||||||
|
|
||||||
|
send(&RpcSend {
|
||||||
|
async: true,
|
||||||
|
service: service,
|
||||||
|
tag: tag,
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
extern fn recv_rpc(slot: *mut ()) -> usize {
|
extern fn recv_rpc(slot: *mut ()) -> usize {
|
||||||
send(&RpcRecvRequest(slot));
|
send(&RpcRecvRequest(slot));
|
||||||
recv!(&RpcRecvReply(ref result) => {
|
recv!(&RpcRecvReply(ref result) => {
|
||||||
|
@ -206,7 +256,7 @@ unsafe fn attribute_writeback(typeinfo: *const ()) {
|
||||||
attributes = attributes.offset(1);
|
attributes = attributes.offset(1);
|
||||||
|
|
||||||
if !(*attribute).tag.is_null() {
|
if !(*attribute).tag.is_null() {
|
||||||
send_rpc(0, (*attribute).tag, [
|
send_async_rpc(0, (*attribute).tag, [
|
||||||
&object as *const _ as *const (),
|
&object as *const _ as *const (),
|
||||||
&(*attribute).name as *const _ as *const (),
|
&(*attribute).name as *const _ as *const (),
|
||||||
(object as usize + (*attribute).offset) as *const ()
|
(object as usize + (*attribute).offset) as *const ()
|
||||||
|
|
|
@ -8,7 +8,7 @@ extern crate rustc_unicode;
|
||||||
extern crate alloc_artiq;
|
extern crate alloc_artiq;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
#[macro_reexport(vec)]
|
#[macro_reexport(vec, format)]
|
||||||
extern crate collections;
|
extern crate collections;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
|
@ -31,52 +31,3 @@ pub mod prelude {
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
|
|
||||||
use core::fmt::Write;
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! print {
|
|
||||||
($($arg:tt)*) => ($crate::print_fmt(format_args!($($arg)*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! println {
|
|
||||||
($fmt:expr) => (print!(concat!($fmt, "\n")));
|
|
||||||
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
|
|
||||||
}
|
|
||||||
|
|
||||||
extern {
|
|
||||||
fn putchar(c: libc::c_int) -> libc::c_int;
|
|
||||||
fn readchar() -> libc::c_char;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Console;
|
|
||||||
|
|
||||||
impl core::fmt::Write for Console {
|
|
||||||
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
|
|
||||||
for c in s.bytes() { unsafe { putchar(c as i32); } }
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print_fmt(args: self::core::fmt::Arguments) {
|
|
||||||
let _ = Console.write_fmt(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[lang = "panic_fmt"]
|
|
||||||
extern fn panic_fmt(args: self::core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
|
||||||
let _ = write!(Console, "panic at {}:{}: {}\n", file, line, args);
|
|
||||||
let _ = write!(Console, "waiting for debugger...\n");
|
|
||||||
unsafe {
|
|
||||||
let _ = readchar();
|
|
||||||
loop { asm!("l.trap 0") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow linking with crates that are built as -Cpanic=unwind even when the root crate
|
|
||||||
// is built with -Cpanic=abort.
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn _Unwind_Resume() -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40400000;
|
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40800080;
|
||||||
pub const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x40440000;
|
pub const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x40840000;
|
||||||
pub const KERNELCPU_LAST_ADDRESS: usize = 0x4fffffff;
|
pub const KERNELCPU_LAST_ADDRESS: usize = 0x4fffffff;
|
||||||
pub const KSUPPORT_HEADER_SIZE: usize = 0x80;
|
pub const KSUPPORT_HEADER_SIZE: usize = 0x80;
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@ pub enum Message<'a> {
|
||||||
WatchdogClear { id: usize },
|
WatchdogClear { id: usize },
|
||||||
|
|
||||||
RpcSend {
|
RpcSend {
|
||||||
|
async: bool,
|
||||||
service: u32,
|
service: u32,
|
||||||
batch: bool,
|
|
||||||
tag: &'a [u8],
|
tag: &'a [u8],
|
||||||
data: *const *const ()
|
data: *const *const ()
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(libc, const_fn, try_borrow, stmt_expr_attributes, repr_simd, asm)]
|
#![feature(libc, const_fn, try_borrow, stmt_expr_attributes, repr_simd, asm,
|
||||||
|
lang_items)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate std_artiq as std;
|
extern crate std_artiq as std;
|
||||||
|
@ -11,13 +12,54 @@ extern crate byteorder;
|
||||||
extern crate fringe;
|
extern crate fringe;
|
||||||
extern crate lwip;
|
extern crate lwip;
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
use logger::BufferLogger;
|
use logger::BufferLogger;
|
||||||
|
|
||||||
|
extern {
|
||||||
|
fn putchar(c: libc::c_int) -> libc::c_int;
|
||||||
|
fn readchar() -> libc::c_char;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => ($crate::print_fmt(format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println {
|
||||||
|
($fmt:expr) => (print!(concat!($fmt, "\n")));
|
||||||
|
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Console;
|
||||||
|
|
||||||
|
impl core::fmt::Write for Console {
|
||||||
|
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
|
||||||
|
for c in s.bytes() { unsafe { putchar(c as i32); } }
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_fmt(args: self::core::fmt::Arguments) {
|
||||||
|
let _ = Console.write_fmt(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[lang = "panic_fmt"]
|
||||||
|
extern fn panic_fmt(args: self::core::fmt::Arguments, file: &'static str, line: u32) -> ! {
|
||||||
|
let _ = write!(Console, "panic at {}:{}: {}\n", file, line, args);
|
||||||
|
let _ = write!(Console, "waiting for debugger...\n");
|
||||||
|
unsafe {
|
||||||
|
let _ = readchar();
|
||||||
|
loop { asm!("l.trap 0") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod board;
|
mod board;
|
||||||
mod config;
|
mod config;
|
||||||
mod clock;
|
mod clock;
|
||||||
mod rtio_crg;
|
mod rtio_crg;
|
||||||
mod mailbox;
|
mod mailbox;
|
||||||
|
mod rpc_queue;
|
||||||
|
|
||||||
mod urc;
|
mod urc;
|
||||||
mod sched;
|
mod sched;
|
||||||
|
@ -29,9 +71,9 @@ mod kernel_proto;
|
||||||
mod session_proto;
|
mod session_proto;
|
||||||
mod moninj_proto;
|
mod moninj_proto;
|
||||||
mod analyzer_proto;
|
mod analyzer_proto;
|
||||||
|
mod rpc_proto;
|
||||||
|
|
||||||
mod kernel;
|
mod kernel;
|
||||||
mod rpc;
|
|
||||||
mod session;
|
mod session;
|
||||||
mod moninj;
|
mod moninj;
|
||||||
#[cfg(has_rtio_analyzer)]
|
#[cfg(has_rtio_analyzer)]
|
||||||
|
@ -44,6 +86,14 @@ extern {
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/git_info.rs"));
|
include!(concat!(env!("OUT_DIR"), "/git_info.rs"));
|
||||||
|
|
||||||
|
// Allow linking with crates that are built as -Cpanic=unwind even if we use -Cpanic=abort.
|
||||||
|
// This is never called.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn _Unwind_Resume() -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern fn rust_main() {
|
pub unsafe extern fn rust_main() {
|
||||||
static mut LOG_BUFFER: [u8; 4096] = [0; 4096];
|
static mut LOG_BUFFER: [u8; 4096] = [0; 4096];
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::slice;
|
#![allow(dead_code)]
|
||||||
use std::io::{self, Read, Write, BufWriter};
|
|
||||||
|
use core::slice;
|
||||||
|
use std::io::{self, Read, Write};
|
||||||
use proto::*;
|
use proto::*;
|
||||||
use self::tag::{Tag, TagIterator, split_tag};
|
use self::tag::{Tag, TagIterator, split_tag};
|
||||||
|
|
||||||
|
@ -74,6 +76,7 @@ unsafe fn recv_value(reader: &mut Read, tag: Tag, data: &mut *mut (),
|
||||||
pub fn recv_return(reader: &mut Read, tag_bytes: &[u8], data: *mut (),
|
pub fn recv_return(reader: &mut Read, tag_bytes: &[u8], data: *mut (),
|
||||||
alloc: &Fn(usize) -> io::Result<*mut ()>) -> io::Result<()> {
|
alloc: &Fn(usize) -> io::Result<*mut ()>) -> io::Result<()> {
|
||||||
let mut it = TagIterator::new(tag_bytes);
|
let mut it = TagIterator::new(tag_bytes);
|
||||||
|
#[cfg(not(ksupport))]
|
||||||
trace!("recv ...->{}", it);
|
trace!("recv ...->{}", it);
|
||||||
|
|
||||||
let tag = it.next().expect("truncated tag");
|
let tag = it.next().expect("truncated tag");
|
||||||
|
@ -98,7 +101,6 @@ unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let writer = &mut BufWriter::new(writer);
|
|
||||||
try!(write_u8(writer, tag.as_u8()));
|
try!(write_u8(writer, tag.as_u8()));
|
||||||
match tag {
|
match tag {
|
||||||
Tag::None => Ok(()),
|
Tag::None => Ok(()),
|
||||||
|
@ -161,14 +163,16 @@ unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_args(writer: &mut Write, tag_bytes: &[u8],
|
pub fn send_args(writer: &mut Write, service: u32, tag_bytes: &[u8],
|
||||||
data: *const *const ()) -> io::Result<()> {
|
data: *const *const ()) -> io::Result<()> {
|
||||||
let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes);
|
let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes);
|
||||||
|
|
||||||
let mut args_it = TagIterator::new(arg_tags_bytes);
|
let mut args_it = TagIterator::new(arg_tags_bytes);
|
||||||
let return_it = TagIterator::new(return_tag_bytes);
|
let return_it = TagIterator::new(return_tag_bytes);
|
||||||
trace!("send ({})->{}", args_it, return_it);
|
#[cfg(not(ksupport))]
|
||||||
|
trace!("send<{}>({})->{}", service, args_it, return_it);
|
||||||
|
|
||||||
|
try!(write_u32(writer, service));
|
||||||
for index in 0.. {
|
for index in 0.. {
|
||||||
if let Some(arg_tag) = args_it.next() {
|
if let Some(arg_tag) = args_it.next() {
|
||||||
let mut data = unsafe { *data.offset(index) };
|
let mut data = unsafe { *data.offset(index) };
|
|
@ -0,0 +1,61 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use core::ptr::{read_volatile, write_volatile};
|
||||||
|
use core::slice;
|
||||||
|
use board;
|
||||||
|
|
||||||
|
const SEND_MAILBOX: *mut usize = (board::mem::MAILBOX_BASE + 4) as *mut usize;
|
||||||
|
const RECV_MAILBOX: *mut usize = (board::mem::MAILBOX_BASE + 8) as *mut usize;
|
||||||
|
|
||||||
|
const QUEUE_BEGIN: usize = 0x40400000;
|
||||||
|
const QUEUE_END: usize = 0x40800000;
|
||||||
|
const QUEUE_CHUNK: usize = 0x1000;
|
||||||
|
|
||||||
|
pub unsafe fn init() {
|
||||||
|
write_volatile(SEND_MAILBOX, QUEUE_BEGIN);
|
||||||
|
write_volatile(RECV_MAILBOX, QUEUE_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(mut addr: usize) -> usize {
|
||||||
|
debug_assert!(addr % QUEUE_CHUNK == 0);
|
||||||
|
debug_assert!(addr >= QUEUE_BEGIN && addr < QUEUE_END);
|
||||||
|
|
||||||
|
addr += QUEUE_CHUNK;
|
||||||
|
if addr == QUEUE_END { addr = QUEUE_BEGIN }
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> bool {
|
||||||
|
unsafe { read_volatile(SEND_MAILBOX) == read_volatile(RECV_MAILBOX) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn full() -> bool {
|
||||||
|
unsafe { next(read_volatile(SEND_MAILBOX)) == read_volatile(RECV_MAILBOX) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueue<T, E, F>(f: F) -> Result<T, E>
|
||||||
|
where F: FnOnce(&mut [u8]) -> Result<T, E> {
|
||||||
|
debug_assert!(!full());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let slice = slice::from_raw_parts_mut(read_volatile(SEND_MAILBOX) as *mut u8, QUEUE_CHUNK);
|
||||||
|
f(slice).and_then(|x| {
|
||||||
|
write_volatile(SEND_MAILBOX, next(read_volatile(SEND_MAILBOX)));
|
||||||
|
Ok(x)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeue<T, E, F>(f: F) -> Result<T, E>
|
||||||
|
where F: FnOnce(&mut [u8]) -> Result<T, E> {
|
||||||
|
debug_assert!(!empty());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
board::flush_cpu_dcache();
|
||||||
|
let slice = slice::from_raw_parts_mut(read_volatile(RECV_MAILBOX) as *mut u8, QUEUE_CHUNK);
|
||||||
|
f(slice).and_then(|x| {
|
||||||
|
write_volatile(RECV_MAILBOX, next(read_volatile(RECV_MAILBOX)));
|
||||||
|
Ok(x)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{mem, str};
|
use std::{mem, str};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt::Write;
|
use std::io::{self, Read, Write, BufWriter};
|
||||||
use std::io::{self, Read};
|
use {config, rtio_crg, clock, mailbox, rpc_queue, kernel};
|
||||||
use {config, rtio_crg, clock, mailbox, kernel};
|
|
||||||
use logger::BufferLogger;
|
use logger::BufferLogger;
|
||||||
use cache::Cache;
|
use cache::Cache;
|
||||||
use urc::Urc;
|
use urc::Urc;
|
||||||
use sched::{ThreadHandle, Waiter, Spawner};
|
use sched::{ThreadHandle, Waiter, Spawner};
|
||||||
use sched::{TcpListener, TcpStream, SocketAddr, IP_ANY};
|
use sched::{TcpListener, TcpStream, SocketAddr, IP_ANY};
|
||||||
|
use byteorder::{ByteOrder, NetworkEndian};
|
||||||
|
|
||||||
use rpc;
|
use rpc_proto as rpc;
|
||||||
use session_proto as host;
|
use session_proto as host;
|
||||||
use kernel_proto as kern;
|
use kernel_proto as kern;
|
||||||
|
|
||||||
|
@ -132,7 +132,8 @@ fn kern_recv_notrace<R, F>(waiter: Waiter, f: F) -> io::Result<R>
|
||||||
where F: FnOnce(&kern::Message) -> io::Result<R> {
|
where F: FnOnce(&kern::Message) -> io::Result<R> {
|
||||||
try!(waiter.until(|| mailbox::receive() != 0));
|
try!(waiter.until(|| mailbox::receive() != 0));
|
||||||
if !kernel::validate(mailbox::receive()) {
|
if !kernel::validate(mailbox::receive()) {
|
||||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid kernel CPU pointer"))
|
let message = format!("invalid kernel CPU pointer 0x{:x}", mailbox::receive());
|
||||||
|
return Err(io::Error::new(io::ErrorKind::InvalidData, message))
|
||||||
}
|
}
|
||||||
|
|
||||||
f(unsafe { mem::transmute::<usize, &kern::Message>(mailbox::receive()) })
|
f(unsafe { mem::transmute::<usize, &kern::Message>(mailbox::receive()) })
|
||||||
|
@ -352,6 +353,7 @@ fn process_kern_message(waiter: Waiter,
|
||||||
kern_recv_dotrace(request);
|
kern_recv_dotrace(request);
|
||||||
match request {
|
match request {
|
||||||
&kern::Log(args) => {
|
&kern::Log(args) => {
|
||||||
|
use std::fmt::Write;
|
||||||
try!(session.log_buffer.write_fmt(args)
|
try!(session.log_buffer.write_fmt(args)
|
||||||
.map_err(|_| io_error("cannot append to session log buffer")));
|
.map_err(|_| io_error("cannot append to session log buffer")));
|
||||||
session.flush_log_buffer();
|
session.flush_log_buffer();
|
||||||
|
@ -383,15 +385,13 @@ fn process_kern_message(waiter: Waiter,
|
||||||
kern_acknowledge()
|
kern_acknowledge()
|
||||||
}
|
}
|
||||||
|
|
||||||
&kern::RpcSend { service, batch, tag, data } => {
|
&kern::RpcSend { async, service, tag, data } => {
|
||||||
match stream {
|
match stream {
|
||||||
None => unexpected!("unexpected RPC in flash kernel"),
|
None => unexpected!("unexpected RPC in flash kernel"),
|
||||||
Some(ref mut stream) => {
|
Some(ref mut stream) => {
|
||||||
try!(host_write(stream, host::Reply::RpcRequest {
|
try!(host_write(stream, host::Reply::RpcRequest));
|
||||||
service: service
|
try!(rpc::send_args(&mut BufWriter::new(stream), service, tag, data));
|
||||||
}));
|
if !async {
|
||||||
try!(rpc::send_args(stream, tag, data));
|
|
||||||
if !batch {
|
|
||||||
session.kernel_state = KernelState::RpcWait
|
session.kernel_state = KernelState::RpcWait
|
||||||
}
|
}
|
||||||
kern_acknowledge()
|
kern_acknowledge()
|
||||||
|
@ -465,12 +465,27 @@ fn process_kern_message(waiter: Waiter,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_kern_queued_rpc(stream: &mut TcpStream,
|
||||||
|
session: &mut Session) -> io::Result<()> {
|
||||||
|
rpc_queue::dequeue(|slice| {
|
||||||
|
trace!("comm<-kern (async RPC)");
|
||||||
|
let length = NetworkEndian::read_u32(slice) as usize;
|
||||||
|
try!(host_write(stream, host::Reply::RpcRequest));
|
||||||
|
try!(stream.write(&slice[4..][..length]));
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn host_kernel_worker(waiter: Waiter,
|
fn host_kernel_worker(waiter: Waiter,
|
||||||
stream: &mut TcpStream,
|
stream: &mut TcpStream,
|
||||||
congress: &mut Congress) -> io::Result<()> {
|
congress: &mut Congress) -> io::Result<()> {
|
||||||
let mut session = Session::new(congress);
|
let mut session = Session::new(congress);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
if !rpc_queue::empty() {
|
||||||
|
try!(process_kern_queued_rpc(stream, &mut session))
|
||||||
|
}
|
||||||
|
|
||||||
if stream.readable() {
|
if stream.readable() {
|
||||||
try!(process_host_message(waiter, stream, &mut session));
|
try!(process_host_message(waiter, stream, &mut session));
|
||||||
}
|
}
|
||||||
|
@ -509,6 +524,10 @@ fn flash_kernel_worker(waiter: Waiter,
|
||||||
try!(kern_run(&mut session));
|
try!(kern_run(&mut session));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
if !rpc_queue::empty() {
|
||||||
|
return Err(io_error("unexpected background RPC in flash kernel"))
|
||||||
|
}
|
||||||
|
|
||||||
if mailbox::receive() != 0 {
|
if mailbox::receive() != 0 {
|
||||||
if try!(process_kern_message(waiter, None, &mut session)) {
|
if try!(process_kern_message(waiter, None, &mut session)) {
|
||||||
return Ok(())
|
return Ok(())
|
||||||
|
|
|
@ -107,7 +107,7 @@ pub enum Reply<'a> {
|
||||||
backtrace: &'a [usize]
|
backtrace: &'a [usize]
|
||||||
},
|
},
|
||||||
|
|
||||||
RpcRequest { service: u32 },
|
RpcRequest,
|
||||||
|
|
||||||
FlashRead(&'a [u8]),
|
FlashRead(&'a [u8]),
|
||||||
FlashOk,
|
FlashOk,
|
||||||
|
@ -170,9 +170,8 @@ impl<'a> Reply<'a> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Reply::RpcRequest { service } => {
|
Reply::RpcRequest => {
|
||||||
try!(write_u8(writer, 10));
|
try!(write_u8(writer, 10));
|
||||||
try!(write_u32(writer, service));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Reply::FlashRead(ref bytes) => {
|
Reply::FlashRead(ref bytes) => {
|
||||||
|
|
|
@ -7,6 +7,8 @@ OBJECTS := flash_storage.o main.o
|
||||||
OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o rtio.o dds.o i2c.o
|
OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o rtio.o dds.o i2c.o
|
||||||
|
|
||||||
RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug
|
RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug
|
||||||
|
CORE_IO_COMMIT := d40c593f42fafbac1ff3d827f6df96338b5b7d8b
|
||||||
|
export CORE_IO_COMMIT
|
||||||
|
|
||||||
CFLAGS += \
|
CFLAGS += \
|
||||||
-I$(LIBALLOC_DIRECTORY) \
|
-I$(LIBALLOC_DIRECTORY) \
|
||||||
|
@ -54,6 +56,7 @@ $(RUSTOUT_DIRECTORY)/libksupport.a:
|
||||||
--manifest-path $(realpath $(RUNTIME_DIRECTORY)/../runtime.rs/libksupport/Cargo.toml) \
|
--manifest-path $(realpath $(RUNTIME_DIRECTORY)/../runtime.rs/libksupport/Cargo.toml) \
|
||||||
--target=or1k-unknown-none -- \
|
--target=or1k-unknown-none -- \
|
||||||
$(shell cat $(BUILDINC_DIRECTORY)/generated/rust-cfg) \
|
$(shell cat $(BUILDINC_DIRECTORY)/generated/rust-cfg) \
|
||||||
|
--cfg ksupport \
|
||||||
-C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s \
|
-C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s \
|
||||||
-L../libcompiler-rt
|
-L../libcompiler-rt
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,14 @@ INCLUDE generated/regions.ld
|
||||||
|
|
||||||
/* First 4M of main memory are reserved for runtime
|
/* First 4M of main memory are reserved for runtime
|
||||||
* code/data/heap, then comes kernel memory.
|
* code/data/heap, then comes kernel memory.
|
||||||
|
* Next 4M of main memory are reserved for
|
||||||
|
* the background RPC queue.
|
||||||
* First 256K of kernel memory are for support code.
|
* First 256K of kernel memory are for support code.
|
||||||
|
* Support code is loaded at ORIGIN-0x80 so that ELF headers
|
||||||
|
* are also loaded.
|
||||||
*/
|
*/
|
||||||
MEMORY {
|
MEMORY {
|
||||||
ksupport (RWX) : ORIGIN = 0x40400000, LENGTH = 0x40000
|
ksupport (RWX) : ORIGIN = 0x40800080, LENGTH = 0x40000
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Kernel stack is at the end of main RAM. */
|
/* Kernel stack is at the end of main RAM. */
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
|
|
||||||
void send_to_log(const char *ptr, size_t length);
|
void send_to_log(const char *ptr, size_t length);
|
||||||
|
|
||||||
#define KERNELCPU_EXEC_ADDRESS 0x40400000
|
#define KERNELCPU_EXEC_ADDRESS 0x40800080
|
||||||
#define KERNELCPU_PAYLOAD_ADDRESS 0x40440000
|
#define KERNELCPU_PAYLOAD_ADDRESS 0x40840000
|
||||||
#define KERNELCPU_LAST_ADDRESS 0x4fffffff
|
#define KERNELCPU_LAST_ADDRESS 0x4fffffff
|
||||||
#define KSUPPORT_HEADER_SIZE 0x80
|
#define KSUPPORT_HEADER_SIZE 0x80
|
||||||
|
|
||||||
|
|
|
@ -74,9 +74,7 @@ SECTIONS
|
||||||
.heap :
|
.heap :
|
||||||
{
|
{
|
||||||
_fheap = .;
|
_fheap = .;
|
||||||
. = ORIGIN(runtime) + LENGTH(runtime)
|
. = ORIGIN(runtime) + LENGTH(runtime);
|
||||||
/* Leave room for ksupport headers. */
|
|
||||||
- 0x1000;
|
|
||||||
_eheap = .;
|
_eheap = .;
|
||||||
} > runtime
|
} > runtime
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue