Update third_party/lang-items to support OpenSK.
This commit is contained in:
24
third_party/lang-items/Cargo.toml
vendored
24
third_party/lang-items/Cargo.toml
vendored
@@ -1,15 +1,19 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libtock_core"
|
name = "lang_items"
|
||||||
version = "0.1.0"
|
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"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
|
||||||
alloc = ["alloc_init", "linked_list_allocator"]
|
|
||||||
alloc_init = []
|
|
||||||
custom_panic_handler = []
|
|
||||||
custom_alloc_error_handler = []
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
linked_list_allocator = { optional = true, version = "=0.8.1", default-features = false }
|
libtock_core = { path = "../../third_party/libtock-rs/core", default-features = false, features = ["alloc_init", "custom_panic_handler", "custom_alloc_error_handler"] }
|
||||||
libtock_codegen = { path = "../codegen" }
|
libtock_drivers = { path = "../libtock-drivers" }
|
||||||
|
linked_list_allocator = { version = "0.8.1", default-features = false }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
debug_allocations = []
|
||||||
|
panic_console = []
|
||||||
|
std = []
|
||||||
|
|||||||
94
third_party/lang-items/src/allocator.rs
vendored
94
third_party/lang-items/src/allocator.rs
vendored
@@ -1,7 +1,16 @@
|
|||||||
|
use crate::util;
|
||||||
use core::alloc::GlobalAlloc;
|
use core::alloc::GlobalAlloc;
|
||||||
use core::alloc::Layout;
|
use core::alloc::Layout;
|
||||||
|
#[cfg(any(feature = "debug_allocations", feature = "panic_console"))]
|
||||||
|
use core::fmt::Write;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::ptr::NonNull;
|
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;
|
use linked_list_allocator::Heap;
|
||||||
|
|
||||||
static mut HEAP: Heap = Heap::empty();
|
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);
|
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 impl GlobalAlloc for TockAllocator {
|
||||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
HEAP.allocate_first_fit(layout)
|
let ptr = HEAP
|
||||||
|
.allocate_first_fit(layout)
|
||||||
.ok()
|
.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) {
|
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)
|
HEAP.deallocate(NonNull::new_unchecked(ptr), layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "arm", target_arch = "riscv32"))]
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOCATOR: TockAllocator = TockAllocator;
|
static ALLOCATOR: TockAllocator = TockAllocator::new();
|
||||||
|
|
||||||
#[cfg(not(feature = "custom_alloc_error_handler"))]
|
|
||||||
#[alloc_error_handler]
|
#[alloc_error_handler]
|
||||||
unsafe fn alloc_error_handler(_: Layout) -> ! {
|
unsafe fn alloc_error_handler(_layout: Layout) -> ! {
|
||||||
use crate::syscalls;
|
util::signal_oom();
|
||||||
|
util::signal_panic();
|
||||||
|
|
||||||
// Print 0x01 using the LowLevelDebug capsule (if available).
|
#[cfg(feature = "panic_console")]
|
||||||
let _ = syscalls::command1_insecure(8, 2, 0x01);
|
{
|
||||||
|
writeln!(Console::new(), "Couldn't allocate: {:?}", _layout).ok();
|
||||||
// Signal a panic using the LowLevelDebug capsule (if available).
|
// Force the kernel to report the panic cause, by reading an invalid address.
|
||||||
let _ = syscalls::command1_insecure(8, 1, 0x01);
|
// The memory protection unit should be setup by the Tock kernel to prevent apps from accessing
|
||||||
|
// address zero.
|
||||||
loop {
|
core::ptr::read_volatile(0 as *const usize);
|
||||||
syscalls::raw::yieldk();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
util::cycle_leds()
|
||||||
}
|
}
|
||||||
|
|||||||
9
third_party/lang-items/src/lib.rs
vendored
Normal file
9
third_party/lang-items/src/lib.rs
vendored
Normal 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;
|
||||||
82
third_party/lang-items/src/panic_handler.rs
vendored
82
third_party/lang-items/src/panic_handler.rs
vendored
@@ -1,72 +1,26 @@
|
|||||||
//! Lang item required to make the normal `main` work in applications
|
use crate::util;
|
||||||
//!
|
#[cfg(feature = "panic_console")]
|
||||||
//! This is how the `start` lang item works:
|
use core::fmt::Write;
|
||||||
//! 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 core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
#[cfg(feature = "panic_console")]
|
||||||
#[lang = "start"]
|
use libtock_drivers::console::Console;
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic_handler(_info: &PanicInfo) -> ! {
|
fn panic_handler(_info: &PanicInfo) -> ! {
|
||||||
// Signal a panic using the LowLevelDebug capsule (if available).
|
util::signal_panic();
|
||||||
super::debug::low_level_status_code(1);
|
|
||||||
|
|
||||||
// Flash all LEDs (if available).
|
#[cfg(feature = "panic_console")]
|
||||||
loop {
|
{
|
||||||
for led in led::all() {
|
let mut console = Console::new();
|
||||||
led.on();
|
writeln!(console, "{}", _info).ok();
|
||||||
}
|
console.flush();
|
||||||
timer::sleep(Duration::from_ms(100));
|
// Force the kernel to report the panic cause, by reading an invalid address.
|
||||||
for led in led::all() {
|
// The memory protection unit should be setup by the Tock kernel to prevent apps from accessing
|
||||||
led.off();
|
// address zero.
|
||||||
}
|
unsafe {
|
||||||
timer::sleep(Duration::from_ms(100));
|
core::ptr::read_volatile(0 as *const usize);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[alloc_error_handler]
|
|
||||||
fn cycle_leds(_: Layout) -> ! {
|
|
||||||
loop {
|
|
||||||
for led in led::all() {
|
|
||||||
led.on();
|
|
||||||
timer::sleep(Duration::from_ms(100));
|
|
||||||
led.off();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
util::flash_all_leds();
|
||||||
}
|
}
|
||||||
|
|||||||
46
third_party/lang-items/src/util.rs
vendored
Normal file
46
third_party/lang-items/src/util.rs
vendored
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user