Process spawn and exit. Get rid of allocator.
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
-name = "embedded-alloc"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8931e47e33c5d3194fbcf9cc82df0919193bd2fa40008f388eb1d28fd9c9ea6b"
-dependencies = [
- "critical-section",
- "linked_list_allocator",
-]
-
-[[package]]
name = "embedded-dma"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
"cortex-m-rt",
"critical-section",
"doa-hallonbrod",
- "embedded-alloc",
"embedded-hal",
"frunk_core",
"fugit",
]
[[package]]
-name = "linked_list_allocator"
-version = "0.10.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
-
-[[package]]
name = "lock_api"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
cortex-m = { version = "0.7", features = ["inline-asm"] }
cortex-m-rt = "0.7"
critical-section = "1.1"
-embedded-alloc = "0.5"
embedded-hal = { version = "0.2.5", features = ["unproven"] }
frunk_core = { version = "0.4", default-features = false }
fugit = "0.3.7"
} INSERT BEFORE .text;
SECTIONS {
- .kheap (NOLOAD) : ALIGN(4) {
- *(.kheap);
- . = ALIGN(4);
- } > SRAM4
-} INSERT AFTER .bss;
-
-SECTIONS {
.appram : {
*(.appram);
. = ALIGN(4);
-use embedded_alloc::Heap;
-
-#[global_allocator]
-#[link_section = ".kgram1"]
-static HEAP: Heap = Heap::empty();
-
-#[link_section = ".kheap"]
-static KERNEL_ARENA: [u8; 0x400] = [0u8; 0x400];
-
-pub fn init_allocator() {
- unsafe {
- let arena_start = &KERNEL_ARENA as *const u8 as usize;
- let size = KERNEL_ARENA.len();
- HEAP.init(arena_start, size);
- }
-}
\ No newline at end of file
-extern crate alloc;
use core::{slice, num::ParseIntError};
use crate::stdlib;
stdlib::print("\r\n");
Ok(())
}
+ "q" => {
+ stdlib::exit();
+ }
+ "dog" => {
+ let tid = stdlib::spawn(dog);
+ if tid == 0xFFFFFFFF {
+ stdlib::print("Failed to launch dog\r\n");
+ } else {
+ stdlib::print("spawned dog at tid ");
+ print_hex_u32(tid);
+ stdlib::print("\r\n");
+ }
+ Ok(())
+ },
+ "ps" => {
+ stdlib::ps();
+ Ok(())
+ }
_ => {
Err(CommandError::BadCommand)
}
}
}
}
+}
+
+fn dog(_base: u32, _size: u32) -> ! {
+ for _ in 0..10 {
+ stdlib::print("woof\r\n");
+ stdlib::sleep(1500);
+ }
+ stdlib::exit();
}
\ No newline at end of file
use core::cell::RefCell;
+use core::fmt;
use critical_section::Mutex;
Keyboard = 3,
}
+impl fmt::Display for CapType {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ CapType::ConsoleRead => write!(f, "ConRead"),
+ CapType::ConsoleWrite => write!(f, "ConWrite"),
+ CapType::Led => write!(f, "LED"),
+ CapType::Keyboard => write!(f, "Keyboard"),
+ }
+ }
+}
+
pub struct CapSet(u32);
impl CapSet {
self.state.take(tid)
}
- fn replace(&mut self, token: CapToken, tid: TaskId) -> bool {
+ fn give(&mut self, token: CapToken, tid: TaskId) -> bool {
self.state.replace(token, tid)
}
}
}).collect()
}
- pub fn replace(&mut self, token: CapToken, tid: TaskId) -> bool {
+ pub fn give(&mut self, token: CapToken, tid: TaskId) -> bool {
let cap_entry = self.capabilities.iter_mut().find(|ce| ce.cap == token.0);
if let Some(cap_entry) = cap_entry {
- cap_entry.replace(token, tid)
+ cap_entry.give(token, tid)
} else {
false
}
-extern crate alloc;
use core::cell::RefCell;
+use core::fmt::Write;
use critical_section::Mutex;
use usb_device::UsbError;
})
}
-pub(crate) fn _print(s: core::fmt::Arguments) {
- let str = alloc::format!("{}", s);
- write(str.as_bytes()).ok();
+pub(crate) fn _printf(s: core::fmt::Arguments) {
+ let mut buf: heapless::Vec<u8, 256> = heapless::Vec::new();
+ write!(&mut buf, "{}", s).expect("write!");
+ let mut bytes_written = 0;
+ while bytes_written < buf.len() {
+ bytes_written += match write(&buf[bytes_written..]) {
+ Ok(n) => n,
+ Err(ConsoleError::Blocked) => 0,
+ Err(_) => panic!("printf"),
+ }
+ }
}
#[macro_export]
macro_rules! kprintf {
($($arg:tt)*) => {{
- $crate::console::_print(core::format_args!($($arg)*));
+ $crate::console::_printf(core::format_args!($($arg)*));
}}
}
#![no_std]
#![no_main]
#![feature(error_in_core)]
+#![feature(slice_internals)]
-mod allocator;
mod apps;
mod asm;
mod capabilities;
use bsp::entry;
use doa_hallonbrod as bsp;
-use allocator::init_allocator;
use capabilities::{init_capabilities, CapType};
use console::init_console;
use task::{init_tasks, with_task_manager};
r0::init_data(&mut __skgram1, &mut __ekgram1, &mut __lkgram1);
}
- init_allocator();
init_peripherals();
init_console();
init_tasks();
+use core::fmt::Write;
use core::panic::PanicInfo;
-use crate::console::write;
+use crate::console::{write, ConsoleError};
#[link_section = ".kgram1"]
static mut ALREADY_PANICKING: bool = false;
-#[panic_handler]
-fn panic(info: &PanicInfo) -> ! {
- unsafe {
- if ALREADY_PANICKING {
- // welp
- loop {}
+fn print_panic(info: &PanicInfo) -> Result<(), ConsoleError> {
+ let mut format_buffer: heapless::Vec<u8, 256> = heapless::Vec::new();
+ write(b"PANIC!\r\n")?;
+ match write!(&mut format_buffer, "{}", info) {
+ Ok(_) => {
+ write(&format_buffer)?;
+ }
+ Err(_) => {
+ write(b"could not get payload")?;
}
- ALREADY_PANICKING = true;
- }
- cortex_m::interrupt::disable();
- write(b"PANIC!\n");
-
- if let Some(p) = info.payload().downcast_ref::<&str>() {
- write(p.as_bytes());
- } else {
- write(b"could not get payload");
}
- write(b"\n");
+ write(b"\n")?;
if let Some(location) = info.location() {
- write(b"at ");
- write(location.file().as_bytes());
- write(b" line ");
- print_dec(location.line());
- write(b":");
- print_dec(location.column());
- write(b"\n");
+ write!(
+ &mut format_buffer,
+ "at {} line {}:{}",
+ location.file(),
+ location.line(),
+ location.column()
+ )
+ .expect("write!");
+ write(&format_buffer)?;
} else {
- write(b"Unknown location\n");
+ write(b"Unknown location\n")?;
}
- write(b"\r\n");
- loop{}
-}
+ write(b"\r\n")?;
-pub fn dec_digit(n: u32) -> u8 {
- b'0' + (n % 10) as u8
+ Ok(())
}
-pub fn format_int_dec(n: u32, buf: &mut [u8]) -> usize {
- if n == 0 {
- buf[buf.len() - 1] = b'0';
- return 1;
- }
-
- let mut n = n;
- let mut c = buf.len() - 1;
- loop {
- buf[c] = dec_digit(n);
- n /= 10;
- if c == 0 || n == 0 {
- break;
+#[panic_handler]
+fn panic(info: &PanicInfo) -> ! {
+ unsafe {
+ if ALREADY_PANICKING {
+ // welp
+ loop {}
}
- c -= 1;
+ ALREADY_PANICKING = true;
}
+ cortex_m::interrupt::disable();
- buf.len() - c
-}
-
-pub fn print_dec<T: Into<u32>>(v: T) {
- let v: u32 = v.into();
- let mut buf = [0u8; 10];
+ print_panic(info).expect("rut roh");
- let n = format_int_dec(v, &mut buf);
- write(&buf[10 - n..]);
-}
\ No newline at end of file
+ loop {}
+}
pub fn led(on: bool) {
unsafe { _svc_call(4, on as u32, 0, 0); }
+}
+
+pub fn exit() -> ! {
+ unsafe { _svc_call(100, 0, 0, 0); }
+ unreachable!();
+}
+
+pub fn spawn(entry: fn(u32, u32) -> !) -> u32 {
+ let entry = entry as u32;
+ unsafe { _svc_call(101, entry, 0, 0) }
+}
+
+pub fn ps() {
+ unsafe { _svc_call(102, 0, 0, 0); }
}
\ No newline at end of file
}
});
}
- _ => (), //panic!("Unknown SVCall"),
+ 100 => {
+ with_task_manager(|tm| tm.exit_current_task());
+ SCB::set_pendsv();
+ }
+ 101 => {
+ let entry = regs.r1 as *const ();
+ let entry = core::mem::transmute(entry);
+ let r = with_task_manager(|tm| {
+ tm.add_task(entry, &[], 10)
+ });
+ match r {
+ Ok(tid) => regs.r0 = tid,
+ Err(_) => regs.r0 = 0xFFFFFFFF,
+ }
+ }
+ 102 => {
+ with_task_manager(|tm| tm.print_tasks());
+ }
+ _ => panic!("Unknown SVCall"),
}
}
use core::arch::global_asm;
use core::cell::RefCell;
-use core::cmp::Ordering;
+use core::fmt::Write;
+use core::slice::sort::quicksort;
use cortex_m::asm::wfi;
use critical_section::Mutex;
use crate::bsp::pac::SCB;
use crate::capabilities::{with_cap_registry, CapToken, CapType, MAX_CAPS};
+use crate::kprintf;
use crate::peripherals::with_peripherals;
use crate::timer::{ticks, Ticks};
regs.r1 = data_size;
let t = TaskEntry {
- id: 0,
+ id: tid,
regs,
data,
data_size: data_size as usize,
if prio_list.is_empty() {
panic!("No scheduleable tasks!");
}
- prio_list.sort_by(|a, b| {
+ quicksort(&mut prio_list, |a, b| {
let ta = &self.tasks[*a];
let tb = &self.tasks[*b];
// Tasks that are I/O ready jump to the head of the queue.
// Otherwise, order by priority.
if ta.io_ready && !tb.io_ready {
- Ordering::Greater
+ false
} else if tb.io_ready && !tb.io_ready {
- Ordering::Less
+ true
} else {
- ta.priority.cmp(&tb.priority)
+ ta.priority < tb.priority
}
});
+ // Remove any I/O ready boosts
+ for i in &prio_list {
+ self.tasks[*i].io_ready = false;
+ }
// TODO: fairness for tasks of the same priority
self.pending_task = prio_list[0];
}
pub(crate) fn task_swap(&mut self, regs: &mut TaskRegisters) {
if self.pending_task == self.current_task {
+ self.tasks[self.current_task].ticks_ran += 1;
return;
}
- // Store the registers of the current task
+ // Store the registers of the current task if it is not exiting
let t = &mut self.tasks[self.current_task];
- t.regs = regs.clone();
+ if t.state == TaskState::Exiting {
+ let mut t = self.tasks.remove(self.current_task);
+ kprintf!("Task {} exited. Ran for {} ticks\r\n", t.id, t.ticks_ran);
+ // Deallocate memory regions
+ for m in &mut self.region_map {
+ if let Some(tid) = m {
+ if *tid == t.id {
+ *m = None;
+ }
+ }
+ }
+ // Reclaim capabilities
+ with_cap_registry(|cr| {
+ let caps = &mut t.caps;
+ while !caps.is_empty() {
+ let c = caps.pop().unwrap();
+ cr.give(c, t.id);
+ }
+ });
+ if self.pending_task > self.current_task {
+ self.pending_task -= 1;
+ }
+ } else {
+ t.regs = regs.clone();
+ }
// Set new task
self.current_task = self.pending_task;
// gets re-run.
t.regs.pc -= 2;
t.state = TaskState::Running;
+ // set I/O ready boost
+ t.io_ready = true;
// Set PendSV to schedule immediately after exiting this
// interrupt.
SCB::set_pendsv();
false
}
}
+
+ pub fn exit_current_task(&mut self) {
+ let t = &mut self.tasks[self.current_task];
+ t.state = TaskState::Exiting;
+ SCB::set_pendsv();
+ }
+
+ pub fn print_tasks(&self) {
+ kprintf!("TID DATA ADDR STATE PRIO TICKS MAPS\r\n");
+ for t in &self.tasks {
+ let mut format_buffer: heapless::Vec<u8, 20> = heapless::Vec::new();
+ write!(&mut format_buffer, "{}", t.state).expect("write!");
+ kprintf!(
+ "{:<7} {:<10X} {:<10} {:<4}{} {:<6} ",
+ t.id,
+ t.data,
+ core::str::from_utf8(&format_buffer).unwrap(),
+ t.priority,
+ if t.io_ready { "+" } else { " " },
+ t.ticks_ran,
+ );
+ for (i, m) in self.region_map.iter().enumerate() {
+ if let Some(tid) = m {
+ if *tid == t.id {
+ kprintf!("{} ", i);
+ }
+ }
+ }
+ kprintf!("\r\n");
+ }
+ }
}
pub fn init_tasks() {
+use core::fmt;
+
use crate::capabilities::{CapToken, MAX_CAPS, CapType};
use crate::task::TaskId;
use crate::timer::Ticks;
/// Waiting for the current number of ticks to equal the value
/// within.
Sleeping(Ticks),
+ /// The task is exiting and will be removed on the next scheduling pass
+ Exiting,
+}
+
+impl fmt::Display for TaskState {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ TaskState::Running => write!(f, "running"),
+ TaskState::Blocked(c) => write!(f, "blocked {}", c),
+ TaskState::Sleeping(_) => write!(f, "sleeping"),
+ TaskState::Exiting => write!(f, "exiting"),
+ }
+ }
}
#[repr(C)]