firmware: migrate rpc_proto to new libio.

This closes an old and horrible issue in that some code in ksupport
may implicitly try to allocate and we'll never know until it crashes
at runtime inside liballoc_stub.

This also removes liballoc_stub.
This also removes ReadExt and WriteExt from libproto.
Hooray!
This commit is contained in:
whitequark 2018-05-14 16:52:14 +00:00
parent 9a1bd66d2c
commit 6a10d54432
14 changed files with 73 additions and 152 deletions

View File

@ -2,10 +2,6 @@
name = "alloc_list" name = "alloc_list"
version = "0.0.0" version = "0.0.0"
[[package]]
name = "alloc_stub"
version = "0.0.0"
[[package]] [[package]]
name = "amp" name = "amp"
version = "0.0.0" version = "0.0.0"
@ -146,15 +142,13 @@ dependencies = [
name = "ksupport" name = "ksupport"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"alloc_stub 0.0.0",
"amp 0.0.0", "amp 0.0.0",
"board 0.0.0", "board 0.0.0",
"build_misoc 0.0.0", "build_misoc 0.0.0",
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dyld 0.0.0", "dyld 0.0.0",
"io 0.0.0",
"proto 0.0.0", "proto 0.0.0",
"std_artiq 0.0.0",
] ]
[[package]] [[package]]
@ -211,7 +205,6 @@ dependencies = [
"dyld 0.0.0", "dyld 0.0.0",
"io 0.0.0", "io 0.0.0",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"std_artiq 0.0.0",
] ]
[[package]] [[package]]

View File

@ -13,10 +13,8 @@ crate-type = ["staticlib"]
build_misoc = { path = "../libbuild_misoc" } build_misoc = { path = "../libbuild_misoc" }
[dependencies] [dependencies]
byteorder = { version = "1.0", default-features = false }
cslice = { version = "0.3" } cslice = { version = "0.3" }
alloc_stub = { path = "../liballoc_stub" } io = { path = "../libio", features = ["byteorder"] }
std_artiq = { path = "../libstd_artiq" }
dyld = { path = "../libdyld" } dyld = { path = "../libdyld" }
board = { path = "../libboard" } board = { path = "../libboard" }
proto = { path = "../libproto" } proto = { path = "../libproto" }

View File

@ -1,31 +1,27 @@
#![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator)] #![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator,
needs_panic_runtime)]
#![no_std] #![no_std]
#![needs_panic_runtime]
extern crate byteorder;
extern crate cslice; extern crate cslice;
extern crate unwind; extern crate unwind;
extern crate libc; extern crate libc;
extern crate alloc_stub; extern crate io;
extern crate std_artiq as std;
extern crate board; extern crate board;
extern crate dyld; extern crate dyld;
extern crate proto; extern crate proto;
extern crate amp; extern crate amp;
use core::{mem, ptr, slice, str}; use core::{mem, ptr, slice, str};
use std::io::Cursor;
use cslice::{CSlice, AsCSlice}; use cslice::{CSlice, AsCSlice};
use alloc_stub::StubAlloc; use io::Cursor;
use board::csr; use board::csr;
use dyld::Library; use dyld::Library;
use proto::{kernel_proto, rpc_proto}; use proto::{kernel_proto, rpc_proto};
use proto::kernel_proto::*; use proto::kernel_proto::*;
use amp::{mailbox, rpc_queue}; use amp::{mailbox, rpc_queue};
#[global_allocator]
static mut ALLOC: StubAlloc = StubAlloc;
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() {}
@ -131,9 +127,9 @@ extern fn rpc_send_async(service: u32, tag: CSlice<u8>, data: *const *const ())
rpc_proto::send_args(&mut writer, service, tag.as_ref(), data)?; rpc_proto::send_args(&mut writer, service, tag.as_ref(), data)?;
writer.position() writer.position()
}; };
proto::WriteExt::write_u32(&mut slice, length as u32) io::proto::ProtoWrite::write_u32(&mut slice, length as u32)
}).unwrap_or_else(|err| { }).unwrap_or_else(|err| {
assert!(err.kind() == std::io::ErrorKind::WriteZero); assert!(err == io::Error::UnexpectedEof);
while !rpc_queue::empty() {} while !rpc_queue::empty() {}
send(&RpcSend { send(&RpcSend {

View File

@ -1,8 +0,0 @@
[package]
authors = ["M-Labs"]
name = "alloc_stub"
version = "0.0.0"
[lib]
name = "alloc_stub"
path = "lib.rs"

View File

@ -1,18 +0,0 @@
#![feature(alloc, allocator_api)]
#![no_std]
extern crate alloc;
use alloc::allocator::{Layout, AllocErr, Alloc};
pub struct StubAlloc;
unsafe impl<'a> Alloc for &'a StubAlloc {
unsafe fn alloc(&mut self, _layout: Layout) -> Result<*mut u8, AllocErr> {
unimplemented!()
}
unsafe fn dealloc(&mut self, _ptr: *mut u8, _layout: Layout) {
unimplemented!()
}
}

View File

@ -99,6 +99,23 @@ pub trait Write {
fn size_hint(&mut self, _min: usize, _max: Option<usize>) {} fn size_hint(&mut self, _min: usize, _max: Option<usize>) {}
} }
#[cfg(not(feature = "std_artiq"))]
impl<'a> Write for &'a mut [u8] {
type WriteError = !;
type FlushError = !;
fn write(&mut self, buf: &[u8]) -> result::Result<usize, Self::WriteError> {
let len = buf.len().min(self.len());
self[..len].copy_from_slice(&buf[..len]);
Ok(len)
}
#[inline]
fn flush(&mut self) -> result::Result<(), Self::FlushError> {
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CursorError { pub enum CursorError {
EndOfBuffer EndOfBuffer

View File

@ -1,15 +1,19 @@
#[cfg(feature = "alloc")]
use core::fmt; use core::fmt;
#[cfg(feature = "alloc")]
use alloc::string; use alloc::string;
use byteorder::{ByteOrder, NetworkEndian}; use byteorder::{ByteOrder, NetworkEndian};
use ::{Read, Write, Error as IoError}; use ::{Read, Write, Error as IoError};
#[cfg(feature = "alloc")]
#[derive(Debug)] #[derive(Debug)]
pub enum ReadStringError<T> { pub enum ReadStringError<T> {
Utf8Error(string::FromUtf8Error), Utf8Error(string::FromUtf8Error),
Other(T) Other(T)
} }
#[cfg(feature = "alloc")]
impl<T: fmt::Display> fmt::Display for ReadStringError<T> { impl<T: fmt::Display> fmt::Display for ReadStringError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@ -21,6 +25,7 @@ impl<T: fmt::Display> fmt::Display for ReadStringError<T> {
} }
} }
#[cfg(feature = "alloc")]
impl<T> From<ReadStringError<IoError<T>>> for IoError<T> impl<T> From<ReadStringError<IoError<T>>> for IoError<T>
{ {
fn from(value: ReadStringError<IoError<T>>) -> IoError<T> { fn from(value: ReadStringError<IoError<T>>) -> IoError<T> {
@ -31,6 +36,7 @@ impl<T> From<ReadStringError<IoError<T>>> for IoError<T>
} }
} }
#[cfg(feature = "alloc")]
#[cfg(feature = "std_artiq")] #[cfg(feature = "std_artiq")]
impl<T> From<ReadStringError<T>> for ::std_artiq::io::Error impl<T> From<ReadStringError<T>> for ::std_artiq::io::Error
where T: Into<::std_artiq::io::Error> where T: Into<::std_artiq::io::Error>

View File

@ -11,6 +11,8 @@ path = "lib.rs"
byteorder = { version = "1.0", default-features = false } byteorder = { version = "1.0", default-features = false }
cslice = { version = "0.3" } cslice = { version = "0.3" }
log = { version = "0.4", default-features = false, optional = true } log = { version = "0.4", default-features = false, optional = true }
io = { path = "../libio", features = ["byteorder", "alloc"] } io = { path = "../libio", features = ["byteorder"] }
std_artiq = { path = "../libstd_artiq", features = ["alloc"] }
dyld = { path = "../libdyld" } dyld = { path = "../libdyld" }
[features]
alloc = ["io/alloc"]

View File

@ -1,8 +1,8 @@
#![no_std] #![no_std]
#![feature(alloc)] #![cfg_attr(feature = "alloc", feature(alloc))]
#[cfg(feature = "alloc")]
extern crate alloc; extern crate alloc;
extern crate byteorder;
extern crate cslice; extern crate cslice;
#[cfg(feature = "log")] #[cfg(feature = "log")]
#[macro_use] #[macro_use]
@ -10,97 +10,17 @@ extern crate log;
extern crate io; extern crate io;
extern crate dyld; extern crate dyld;
extern crate std_artiq as std;
// Internal protocols. // Internal protocols.
pub mod kernel_proto; pub mod kernel_proto;
// External protocols. // External protocols.
#[cfg(feature = "alloc")]
pub mod mgmt_proto; pub mod mgmt_proto;
#[cfg(feature = "alloc")]
pub mod analyzer_proto; pub mod analyzer_proto;
#[cfg(feature = "alloc")]
pub mod moninj_proto; pub mod moninj_proto;
#[cfg(feature = "alloc")]
pub mod session_proto; pub mod session_proto;
pub mod rpc_proto; pub mod rpc_proto;
use std::io::{Read, Write, Result, Error, ErrorKind};
use std::vec::Vec;
use std::string::String;
use byteorder::{ByteOrder, NetworkEndian};
pub trait ReadExt: Read {
fn read_u8(&mut self) -> Result<u8> {
let mut bytes = [0; 1];
self.read_exact(&mut bytes)?;
Ok(bytes[0])
}
fn read_u16(&mut self) -> Result<u16> {
let mut bytes = [0; 2];
self.read_exact(&mut bytes)?;
Ok(NetworkEndian::read_u16(&bytes))
}
fn read_u32(&mut self) -> Result<u32> {
let mut bytes = [0; 4];
self.read_exact(&mut bytes)?;
Ok(NetworkEndian::read_u32(&bytes))
}
fn read_u64(&mut self) -> Result<u64> {
let mut bytes = [0; 8];
self.read_exact(&mut bytes)?;
Ok(NetworkEndian::read_u64(&bytes))
}
fn read_bytes(&mut self) -> Result<Vec<u8>> {
let length = self.read_u32()?;
let mut value = Vec::new();
value.resize(length as usize, 0);
self.read_exact(&mut value)?;
Ok(value)
}
fn read_string(&mut self) -> Result<String> {
let bytes = self.read_bytes()?;
String::from_utf8(bytes)
.map_err(|_| Error::new(ErrorKind::InvalidData, "invalid UTF-8"))
}
}
impl<R: Read + ?Sized> ReadExt for R {}
pub trait WriteExt: Write {
fn write_u8(&mut self, value: u8) -> Result<()> {
let bytes = [value; 1];
self.write_all(&bytes)
}
fn write_u16(&mut self, value: u16) -> Result<()> {
let mut bytes = [0; 2];
NetworkEndian::write_u16(&mut bytes, value);
self.write_all(&bytes)
}
fn write_u32(&mut self, value: u32) -> Result<()> {
let mut bytes = [0; 4];
NetworkEndian::write_u32(&mut bytes, value);
self.write_all(&bytes)
}
fn write_u64(&mut self, value: u64) -> Result<()> {
let mut bytes = [0; 8];
NetworkEndian::write_u64(&mut bytes, value);
self.write_all(&bytes)
}
fn write_bytes(&mut self, value: &[u8]) -> Result<()> {
self.write_u32(value.len() as u32)?;
self.write_all(value)
}
fn write_string(&mut self, value: &str) -> Result<()> {
self.write_bytes(value.as_bytes())
}
}
impl<W: Write + ?Sized> WriteExt for W {}

View File

@ -1,11 +1,16 @@
use std::io::{self, Read, Write}; use core::str;
use std::str;
use cslice::{CSlice, CMutSlice}; use cslice::{CSlice, CMutSlice};
use {ReadExt, WriteExt};
use io::{Read, Write, Result};
use io::proto::{ProtoRead, ProtoWrite};
use self::tag::{Tag, TagIterator, split_tag}; use self::tag::{Tag, TagIterator, split_tag};
unsafe fn recv_value(reader: &mut Read, tag: Tag, data: &mut *mut (), unsafe fn recv_value<T>(reader: &mut T, tag: Tag, data: &mut *mut (),
alloc: &Fn(usize) -> io::Result<*mut ()>) -> io::Result<()> { alloc: &Fn(usize) -> Result<*mut (), T::ReadError>)
-> Result<(), T::ReadError>
where T: Read + ?Sized
{
macro_rules! consume_value { macro_rules! consume_value {
($ty:ty, |$ptr:ident| $map:expr) => ({ ($ty:ty, |$ptr:ident| $map:expr) => ({
let $ptr = (*data) as *mut $ty; let $ptr = (*data) as *mut $ty;
@ -71,8 +76,11 @@ 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<T>(reader: &mut T, tag_bytes: &[u8], data: *mut (),
alloc: &Fn(usize) -> io::Result<*mut ()>) -> io::Result<()> { alloc: &Fn(usize) -> Result<*mut (), T::ReadError>)
-> Result<(), T::ReadError>
where T: Read + ?Sized
{
let mut it = TagIterator::new(tag_bytes); let mut it = TagIterator::new(tag_bytes);
#[cfg(feature = "log")] #[cfg(feature = "log")]
debug!("recv ...->{}", it); debug!("recv ...->{}", it);
@ -84,7 +92,10 @@ pub fn recv_return(reader: &mut Read, tag_bytes: &[u8], data: *mut (),
Ok(()) Ok(())
} }
unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::Result<()> { unsafe fn send_value<T>(writer: &mut T, tag: Tag, data: &mut *const ())
-> Result<(), T::WriteError>
where T: Write + ?Sized
{
macro_rules! consume_value { macro_rules! consume_value {
($ty:ty, |$ptr:ident| $map:expr) => ({ ($ty:ty, |$ptr:ident| $map:expr) => ({
let $ptr = (*data) as *const $ty; let $ptr = (*data) as *const $ty;
@ -158,8 +169,10 @@ unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::
} }
} }
pub fn send_args(writer: &mut Write, service: u32, tag_bytes: &[u8], pub fn send_args<T>(writer: &mut T, service: u32, tag_bytes: &[u8], data: *const *const ())
data: *const *const ()) -> io::Result<()> { -> Result<(), T::WriteError>
where T: Write + ?Sized
{
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);

View File

@ -19,13 +19,13 @@ cslice = { version = "0.3" }
log = { version = "0.4", default-features = false } log = { version = "0.4", default-features = false }
managed = { version = "0.6", default-features = false, features = ["alloc", "map"] } managed = { version = "0.6", default-features = false, features = ["alloc", "map"] }
unwind_backtrace = { path = "../libunwind_backtrace" } unwind_backtrace = { path = "../libunwind_backtrace" }
io = { path = "../libio", features = ["std_artiq"] } io = { path = "../libio", features = ["byteorder", "std_artiq"] }
board = { path = "../libboard", features = ["uart_console", "smoltcp"] } board = { path = "../libboard", features = ["uart_console", "smoltcp"] }
alloc_list = { path = "../liballoc_list" } alloc_list = { path = "../liballoc_list" }
std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] }
logger_artiq = { path = "../liblogger_artiq" } logger_artiq = { path = "../liblogger_artiq" }
board_artiq = { path = "../libboard_artiq" } board_artiq = { path = "../libboard_artiq" }
proto = { path = "../libproto", features = ["log"] } proto = { path = "../libproto", features = ["log", "alloc"] }
amp = { path = "../libamp" } amp = { path = "../libamp" }
drtioaux = { path = "../libdrtioaux" } drtioaux = { path = "../libdrtioaux" }

View File

@ -12,6 +12,7 @@ extern crate smoltcp;
extern crate alloc_list; extern crate alloc_list;
extern crate unwind_backtrace; extern crate unwind_backtrace;
extern crate io;
#[macro_use] #[macro_use]
extern crate std_artiq as std; extern crate std_artiq as std;
extern crate logger_artiq; extern crate logger_artiq;

View File

@ -1,10 +1,11 @@
use board::boot;
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
use log::{self, LevelFilter}; use log::{self, LevelFilter};
use io::proto::ProtoWrite;
use board::boot;
use logger_artiq::BufferLogger; use logger_artiq::BufferLogger;
use sched::Io; use sched::Io;
use sched::{TcpListener, TcpStream}; use sched::{TcpListener, TcpStream};
use proto::WriteExt;
use mgmt_proto::*; use mgmt_proto::*;
use profiler; use profiler;

View File

@ -313,12 +313,12 @@ fn process_host_message(io: &Io,
})?; })?;
rpc::recv_return(stream, &tag, slot, &|size| { rpc::recv_return(stream, &tag, slot, &|size| {
kern_send(io, &kern::RpcRecvReply(Ok(size)))?; kern_send(io, &kern::RpcRecvReply(Ok(size)))?;
kern_recv(io, |reply| { Ok(kern_recv(io, |reply| {
match reply { match reply {
&kern::RpcRecvRequest(slot) => Ok(slot), &kern::RpcRecvRequest(slot) => Ok(slot),
other => unexpected!("unexpected reply from kernel CPU: {:?}", other) other => unexpected!("unexpected reply from kernel CPU: {:?}", other)
} }
}) })?)
})?; })?;
kern_send(io, &kern::RpcRecvReply(Ok(0)))?; kern_send(io, &kern::RpcRecvReply(Ok(0)))?;