Update third_party/lang-items to support OpenSK.

This commit is contained in:
Guillaume Endignoux
2020-07-10 10:33:44 +02:00
parent fbc7044328
commit 76c0840354
5 changed files with 166 additions and 89 deletions

View File

@@ -1,15 +1,19 @@
[package]
name = "libtock_core"
name = "lang_items"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
authors = [
"Tock Project Developers <tock-dev@googlegroups.com>"
"Guillaume Endignoux <guillaumee@google.com>",
]
license = "MIT/Apache-2.0"
edition = "2018"
[features]
alloc = ["alloc_init", "linked_list_allocator"]
alloc_init = []
custom_panic_handler = []
custom_alloc_error_handler = []
[dependencies]
linked_list_allocator = { optional = true, version = "=0.8.1", default-features = false }
libtock_codegen = { path = "../codegen" }
libtock_core = { path = "../../third_party/libtock-rs/core", default-features = false, features = ["alloc_init", "custom_panic_handler", "custom_alloc_error_handler"] }
libtock_drivers = { path = "../libtock-drivers" }
linked_list_allocator = { version = "0.8.1", default-features = false }
[features]
debug_allocations = []
panic_console = []
std = []

View File

@@ -1,7 +1,16 @@
use crate::util;
use core::alloc::GlobalAlloc;
use core::alloc::Layout;
#[cfg(any(feature = "debug_allocations", feature = "panic_console"))]
use core::fmt::Write;
use core::ptr;
use core::ptr::NonNull;
#[cfg(feature = "debug_allocations")]
use core::sync::atomic;
#[cfg(feature = "debug_allocations")]
use core::sync::atomic::AtomicUsize;
#[cfg(any(feature = "debug_allocations", feature = "panic_console"))]
use libtock_drivers::console::Console;
use linked_list_allocator::Heap;
static mut HEAP: Heap = Heap::empty();
@@ -11,35 +20,90 @@ unsafe fn libtock_alloc_init(app_heap_start: usize, app_heap_size: usize) {
HEAP.init(app_heap_start, app_heap_size);
}
struct TockAllocator;
// With the "debug_allocations" feature, we use `AtomicUsize` to store the
// statistics because:
// - it is `Sync`, so we can use it in a static object (the allocator),
// - it implements interior mutability, so we can use it in the allocator
// methods (that take an immutable `&self` reference).
struct TockAllocator {
#[cfg(feature = "debug_allocations")]
count: AtomicUsize,
#[cfg(feature = "debug_allocations")]
size: AtomicUsize,
}
impl TockAllocator {
const fn new() -> TockAllocator {
TockAllocator {
#[cfg(feature = "debug_allocations")]
count: AtomicUsize::new(0),
#[cfg(feature = "debug_allocations")]
size: AtomicUsize::new(0),
}
}
}
unsafe impl GlobalAlloc for TockAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
HEAP.allocate_first_fit(layout)
let ptr = HEAP
.allocate_first_fit(layout)
.ok()
.map_or(ptr::null_mut(), NonNull::as_ptr)
.map_or(ptr::null_mut(), NonNull::as_ptr);
#[cfg(feature = "debug_allocations")]
{
self.count.fetch_add(1, atomic::Ordering::SeqCst);
self.size.fetch_add(layout.size(), atomic::Ordering::SeqCst);
writeln!(
Console::new(),
"alloc[{}, {}] = {:?} ({} ptrs, {} bytes)",
layout.size(),
layout.align(),
ptr,
self.count.load(atomic::Ordering::SeqCst),
self.size.load(atomic::Ordering::SeqCst)
)
.unwrap();
}
ptr
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
#[cfg(feature = "debug_allocations")]
{
self.count.fetch_sub(1, atomic::Ordering::SeqCst);
self.size.fetch_sub(layout.size(), atomic::Ordering::SeqCst);
writeln!(
Console::new(),
"dealloc[{}, {}] = {:?} ({} ptrs, {} bytes)",
layout.size(),
layout.align(),
ptr,
self.count.load(atomic::Ordering::SeqCst),
self.size.load(atomic::Ordering::SeqCst)
)
.unwrap();
}
HEAP.deallocate(NonNull::new_unchecked(ptr), layout)
}
}
#[cfg(any(target_arch = "arm", target_arch = "riscv32"))]
#[global_allocator]
static ALLOCATOR: TockAllocator = TockAllocator;
static ALLOCATOR: TockAllocator = TockAllocator::new();
#[cfg(not(feature = "custom_alloc_error_handler"))]
#[alloc_error_handler]
unsafe fn alloc_error_handler(_: Layout) -> ! {
use crate::syscalls;
unsafe fn alloc_error_handler(_layout: Layout) -> ! {
util::signal_oom();
util::signal_panic();
// Print 0x01 using the LowLevelDebug capsule (if available).
let _ = syscalls::command1_insecure(8, 2, 0x01);
// Signal a panic using the LowLevelDebug capsule (if available).
let _ = syscalls::command1_insecure(8, 1, 0x01);
loop {
syscalls::raw::yieldk();
#[cfg(feature = "panic_console")]
{
writeln!(Console::new(), "Couldn't allocate: {:?}", _layout).ok();
// Force the kernel to report the panic cause, by reading an invalid address.
// The memory protection unit should be setup by the Tock kernel to prevent apps from accessing
// address zero.
core::ptr::read_volatile(0 as *const usize);
}
util::cycle_leds()
}

9
third_party/lang-items/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,9 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![feature(alloc_error_handler)]
#[cfg(not(feature = "std"))]
mod allocator;
#[cfg(not(feature = "std"))]
mod panic_handler;
#[cfg(not(feature = "std"))]
mod util;

View File

@@ -1,72 +1,26 @@
//! Lang item required to make the normal `main` work in applications
//!
//! This is how the `start` lang item works:
//! When `rustc` compiles a binary crate, it creates a `main` function that looks
//! like this:
//!
//! ```
//! #[export_name = "main"]
//! pub extern "C" fn rustc_main(argc: isize, argv: *const *const u8) -> isize {
//! start(main, argc, argv)
//! }
//! ```
//!
//! Where `start` is this function and `main` is the binary crate's `main`
//! function.
//!
//! The final piece is that the entry point of our program, _start, has to call
//! `rustc_main`. That's covered by the `_start` function in the root of this
//! crate.
use crate::led;
use crate::timer;
use crate::timer::Duration;
use core::alloc::Layout;
use crate::util;
#[cfg(feature = "panic_console")]
use core::fmt::Write;
use core::panic::PanicInfo;
#[lang = "start"]
extern "C" fn start<T>(main: fn() -> T, _argc: isize, _argv: *const *const u8) -> i32
where
T: Termination,
{
main().report()
}
pub trait Termination {
fn report(self) -> i32;
}
impl Termination for () {
fn report(self) -> i32 {
0
}
}
#[cfg(feature = "panic_console")]
use libtock_drivers::console::Console;
#[panic_handler]
fn panic_handler(_info: &PanicInfo) -> ! {
// Signal a panic using the LowLevelDebug capsule (if available).
super::debug::low_level_status_code(1);
util::signal_panic();
// Flash all LEDs (if available).
loop {
for led in led::all() {
led.on();
}
timer::sleep(Duration::from_ms(100));
for led in led::all() {
led.off();
}
timer::sleep(Duration::from_ms(100));
}
}
#[alloc_error_handler]
fn cycle_leds(_: Layout) -> ! {
loop {
for led in led::all() {
led.on();
timer::sleep(Duration::from_ms(100));
led.off();
#[cfg(feature = "panic_console")]
{
let mut console = Console::new();
writeln!(console, "{}", _info).ok();
console.flush();
// Force the kernel to report the panic cause, by reading an invalid address.
// The memory protection unit should be setup by the Tock kernel to prevent apps from accessing
// address zero.
unsafe {
core::ptr::read_volatile(0 as *const usize);
}
}
util::flash_all_leds();
}

46
third_party/lang-items/src/util.rs vendored Normal file
View File

@@ -0,0 +1,46 @@
use libtock_drivers::led;
use libtock_drivers::timer::{self, Duration};
// Signal a panic using the LowLevelDebug capsule (if available).
pub fn signal_panic() {
let _ = libtock_core::syscalls::command1_insecure(8, 1, 1);
}
// Signal an out-of-memory error using the LowLevelDebug capsule (if available).
pub fn signal_oom() {
let _ = libtock_core::syscalls::command1_insecure(8, 2, 1);
}
pub fn flash_all_leds() -> ! {
// Flash all LEDs (if available). All errors from syscalls are ignored: we are already inside a
// panic handler so there is nothing much to do if simple drivers (timer, LEDs) don't work.
loop {
if let Ok(leds) = led::all() {
for led in leds {
let _ = led.on();
}
}
let _ = timer::sleep(Duration::from_ms(100));
if let Ok(leds) = led::all() {
for led in leds {
let _ = led.off();
}
}
let _ = timer::sleep(Duration::from_ms(100));
}
}
pub fn cycle_leds() -> ! {
// Cycle though all LEDs (if available). All errors from syscalls are ignored: we are already
// inside an error handler so there is nothing much to do if simple drivers (timer, LEDs) don't
// work.
loop {
if let Ok(leds) = led::all() {
for led in leds {
let _ = led.on();
let _ = timer::sleep(Duration::from_ms(100));
let _ = led.off();
}
}
}
}