2
0
mirror of https://github.com/m-labs/artiq.git synced 2024-12-25 03:08:27 +08:00

runtime: implement prototype background RPCs.

This commit is contained in:
whitequark 2016-10-29 21:34:25 +00:00
parent c656a53532
commit 2ac85cd40f
18 changed files with 252 additions and 87 deletions

View File

@ -7,7 +7,7 @@ from misoc.integration.soc_core import mem_decoder
class KernelCPU(Module):
def __init__(self, platform,
exec_address=0x40400000,
exec_address=0x40800000,
main_mem_origin=0x40000000,
l2_size=8192):
self._reset = CSRStorage(reset=1)

View File

@ -16,7 +16,7 @@ path = "src/lib.rs"
std_artiq = { path = "libstd_artiq" }
lwip = { path = "liblwip", default-features = false }
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" }
byteorder = { version = "0.5", default-features = false }

View File

@ -1,4 +1,26 @@
[root]
name = "ksupport"
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"

View File

@ -8,6 +8,10 @@ name = "ksupport"
path = "lib.rs"
crate-type = ["staticlib"]
[dependencies]
std_artiq = { path = "../libstd_artiq" }
byteorder = { version = "0.5", default-features = false }
[profile.dev]
panic = 'unwind'
opt-level = 2

View File

@ -91,6 +91,7 @@ static mut API: &'static [(&'static str, *const ())] = &[
api!(watchdog_clear = ::watchdog_clear),
api!(send_rpc = ::send_rpc),
api!(send_async_rpc = ::send_async_rpc),
api!(recv_rpc = ::recv_rpc),
api!(cache_get = ::cache_get),

View File

@ -1,5 +1,4 @@
use core::{ptr, slice, str};
use core::slice::SliceExt;
use libc::{c_void, c_char, c_int, size_t};
#[allow(non_camel_case_types)]

View File

@ -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]
#![needs_panic_runtime]
#[macro_use]
extern crate std_artiq as std;
extern crate libc;
extern crate byteorder;
#[path = "../src/board.rs"]
mod board;
#[path = "../src/mailbox.rs"]
mod mailbox;
#[path = "../src/rpc_queue.rs"]
mod rpc_queue;
#[path = "../src/proto.rs"]
mod proto;
#[path = "../src/kernel_proto.rs"]
mod kernel_proto;
#[path = "../src/rpc_proto.rs"]
mod rpc_proto;
mod dyld;
mod api;
use core::{mem, ptr, slice, str};
use std::io::Cursor;
use libc::{c_char, size_t};
use kernel_proto::*;
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) {
unsafe { mailbox::send(request as *const _ as usize) }
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)) };
send(&RpcSend {
service: service as u32,
batch: service == 0,
async: false,
service: service,
tag: tag,
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 {
send(&RpcRecvRequest(slot));
recv!(&RpcRecvReply(ref result) => {
@ -206,7 +256,7 @@ unsafe fn attribute_writeback(typeinfo: *const ()) {
attributes = attributes.offset(1);
if !(*attribute).tag.is_null() {
send_rpc(0, (*attribute).tag, [
send_async_rpc(0, (*attribute).tag, [
&object as *const _ as *const (),
&(*attribute).name as *const _ as *const (),
(object as usize + (*attribute).offset) as *const ()

View File

@ -8,7 +8,7 @@ extern crate rustc_unicode;
extern crate alloc_artiq;
extern crate alloc;
#[macro_use]
#[macro_reexport(vec)]
#[macro_reexport(vec, format)]
extern crate collections;
extern crate libc;
@ -31,52 +31,3 @@ pub mod prelude {
pub mod error;
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 {}
}

View File

@ -3,8 +3,8 @@
use core::marker::PhantomData;
use core::fmt;
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40400000;
pub const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x40440000;
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40800080;
pub const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x40840000;
pub const KERNELCPU_LAST_ADDRESS: usize = 0x4fffffff;
pub const KSUPPORT_HEADER_SIZE: usize = 0x80;
@ -42,8 +42,8 @@ pub enum Message<'a> {
WatchdogClear { id: usize },
RpcSend {
async: bool,
service: u32,
batch: bool,
tag: &'a [u8],
data: *const *const ()
},

View File

@ -1,5 +1,6 @@
#![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]
extern crate std_artiq as std;
@ -11,13 +12,54 @@ extern crate byteorder;
extern crate fringe;
extern crate lwip;
use core::fmt::Write;
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 config;
mod clock;
mod rtio_crg;
mod mailbox;
mod rpc_queue;
mod urc;
mod sched;
@ -29,9 +71,9 @@ mod kernel_proto;
mod session_proto;
mod moninj_proto;
mod analyzer_proto;
mod rpc_proto;
mod kernel;
mod rpc;
mod session;
mod moninj;
#[cfg(has_rtio_analyzer)]
@ -44,6 +86,14 @@ extern {
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]
pub unsafe extern fn rust_main() {
static mut LOG_BUFFER: [u8; 4096] = [0; 4096];

View File

@ -1,5 +1,7 @@
use std::slice;
use std::io::{self, Read, Write, BufWriter};
#![allow(dead_code)]
use core::slice;
use std::io::{self, Read, Write};
use proto::*;
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 (),
alloc: &Fn(usize) -> io::Result<*mut ()>) -> io::Result<()> {
let mut it = TagIterator::new(tag_bytes);
#[cfg(not(ksupport))]
trace!("recv ...->{}", it);
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()));
match tag {
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<()> {
let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes);
let mut args_it = TagIterator::new(arg_tags_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.. {
if let Some(arg_tag) = args_it.next() {
let mut data = unsafe { *data.offset(index) };

View File

@ -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)
})
}
}

View File

@ -1,16 +1,16 @@
use std::prelude::v1::*;
use std::{mem, str};
use std::cell::RefCell;
use std::fmt::Write;
use std::io::{self, Read};
use {config, rtio_crg, clock, mailbox, kernel};
use std::io::{self, Read, Write, BufWriter};
use {config, rtio_crg, clock, mailbox, rpc_queue, kernel};
use logger::BufferLogger;
use cache::Cache;
use urc::Urc;
use sched::{ThreadHandle, Waiter, Spawner};
use sched::{TcpListener, TcpStream, SocketAddr, IP_ANY};
use byteorder::{ByteOrder, NetworkEndian};
use rpc;
use rpc_proto as rpc;
use session_proto as host;
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> {
try!(waiter.until(|| mailbox::receive() != 0));
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()) })
@ -352,6 +353,7 @@ fn process_kern_message(waiter: Waiter,
kern_recv_dotrace(request);
match request {
&kern::Log(args) => {
use std::fmt::Write;
try!(session.log_buffer.write_fmt(args)
.map_err(|_| io_error("cannot append to session log buffer")));
session.flush_log_buffer();
@ -383,15 +385,13 @@ fn process_kern_message(waiter: Waiter,
kern_acknowledge()
}
&kern::RpcSend { service, batch, tag, data } => {
&kern::RpcSend { async, service, tag, data } => {
match stream {
None => unexpected!("unexpected RPC in flash kernel"),
Some(ref mut stream) => {
try!(host_write(stream, host::Reply::RpcRequest {
service: service
}));
try!(rpc::send_args(stream, tag, data));
if !batch {
try!(host_write(stream, host::Reply::RpcRequest));
try!(rpc::send_args(&mut BufWriter::new(stream), service, tag, data));
if !async {
session.kernel_state = KernelState::RpcWait
}
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,
stream: &mut TcpStream,
congress: &mut Congress) -> io::Result<()> {
let mut session = Session::new(congress);
loop {
if !rpc_queue::empty() {
try!(process_kern_queued_rpc(stream, &mut session))
}
if stream.readable() {
try!(process_host_message(waiter, stream, &mut session));
}
@ -509,6 +524,10 @@ fn flash_kernel_worker(waiter: Waiter,
try!(kern_run(&mut session));
loop {
if !rpc_queue::empty() {
return Err(io_error("unexpected background RPC in flash kernel"))
}
if mailbox::receive() != 0 {
if try!(process_kern_message(waiter, None, &mut session)) {
return Ok(())

View File

@ -107,7 +107,7 @@ pub enum Reply<'a> {
backtrace: &'a [usize]
},
RpcRequest { service: u32 },
RpcRequest,
FlashRead(&'a [u8]),
FlashOk,
@ -170,9 +170,8 @@ impl<'a> Reply<'a> {
}
},
Reply::RpcRequest { service } => {
Reply::RpcRequest => {
try!(write_u8(writer, 10));
try!(write_u32(writer, service));
},
Reply::FlashRead(ref bytes) => {

View File

@ -7,6 +7,8 @@ OBJECTS := flash_storage.o main.o
OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o rtio.o dds.o i2c.o
RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug
CORE_IO_COMMIT := d40c593f42fafbac1ff3d827f6df96338b5b7d8b
export CORE_IO_COMMIT
CFLAGS += \
-I$(LIBALLOC_DIRECTORY) \
@ -54,6 +56,7 @@ $(RUSTOUT_DIRECTORY)/libksupport.a:
--manifest-path $(realpath $(RUNTIME_DIRECTORY)/../runtime.rs/libksupport/Cargo.toml) \
--target=or1k-unknown-none -- \
$(shell cat $(BUILDINC_DIRECTORY)/generated/rust-cfg) \
--cfg ksupport \
-C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s \
-L../libcompiler-rt

View File

@ -6,10 +6,14 @@ INCLUDE generated/regions.ld
/* First 4M of main memory are reserved for runtime
* 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.
* Support code is loaded at ORIGIN-0x80 so that ELF headers
* are also loaded.
*/
MEMORY {
ksupport (RWX) : ORIGIN = 0x40400000, LENGTH = 0x40000
ksupport (RWX) : ORIGIN = 0x40800080, LENGTH = 0x40000
}
/* Kernel stack is at the end of main RAM. */

View File

@ -8,8 +8,8 @@
void send_to_log(const char *ptr, size_t length);
#define KERNELCPU_EXEC_ADDRESS 0x40400000
#define KERNELCPU_PAYLOAD_ADDRESS 0x40440000
#define KERNELCPU_EXEC_ADDRESS 0x40800080
#define KERNELCPU_PAYLOAD_ADDRESS 0x40840000
#define KERNELCPU_LAST_ADDRESS 0x4fffffff
#define KSUPPORT_HEADER_SIZE 0x80

View File

@ -74,9 +74,7 @@ SECTIONS
.heap :
{
_fheap = .;
. = ORIGIN(runtime) + LENGTH(runtime)
/* Leave room for ksupport headers. */
- 0x1000;
. = ORIGIN(runtime) + LENGTH(runtime);
_eheap = .;
} > runtime