commit:6971c7c4b333fa9c81155d8296d881b08579a77c
author:Chip
committer:Chip
date:Tue Sep 26 01:29:45 2023 -0500
parents:af12f7225ad5e6ca1f649ec127fbeccca8679398
Process spawn and exit. Get rid of allocator.
diff --git a/Cargo.lock b/Cargo.lock
line changes: +0/-17
index 084812d..1e94e01
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -128,16 +128,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 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"
@@ -224,7 +214,6 @@ dependencies = [
  "cortex-m-rt",
  "critical-section",
  "doa-hallonbrod",
- "embedded-alloc",
  "embedded-hal",
  "frunk_core",
  "fugit",
@@ -267,12 +256,6 @@ dependencies = [
 ]
 
 [[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"

diff --git a/Cargo.toml b/Cargo.toml
line changes: +0/-1
index c5a2070..8ac5ed7
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,7 +7,6 @@ edition = "2021"
 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"

diff --git a/memory.x b/memory.x
line changes: +0/-7
index 5eed022..9cae830
--- a/memory.x
+++ b/memory.x
@@ -17,13 +17,6 @@ SECTIONS {
 } INSERT BEFORE .text;
 
 SECTIONS {
-    .kheap (NOLOAD) : ALIGN(4) {
-        *(.kheap);
-        . = ALIGN(4);
-    } > SRAM4
-} INSERT AFTER .bss;
-
-SECTIONS {
     .appram : {
         *(.appram);
         . = ALIGN(4);

diff --git a/src/allocator.rs b/src/allocator.rs
line changes: +0/-16
index c5ca87c..0000000
--- a/src/allocator.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-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

diff --git a/src/apps/shell.rs b/src/apps/shell.rs
line changes: +26/-1
index 5856dc2..cdd5999
--- a/src/apps/shell.rs
+++ b/src/apps/shell.rs
@@ -1,4 +1,3 @@
-extern crate alloc;
 use core::{slice, num::ParseIntError};
 
 use crate::stdlib;
@@ -109,6 +108,24 @@ fn parse_cmdline(cmdline: &str) -> Result<(), CommandError> {
             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)
         }
@@ -130,4 +147,12 @@ pub fn shell(base: u32, _size: u32) -> ! {
             }
         }
     }
+}
+
+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

diff --git a/src/capabilities.rs b/src/capabilities.rs
line changes: +15/-3
index fdf5ad0..68a5f50
--- a/src/capabilities.rs
+++ b/src/capabilities.rs
@@ -1,4 +1,5 @@
 use core::cell::RefCell;
+use core::fmt;
 
 use critical_section::Mutex;
 
@@ -16,6 +17,17 @@ pub enum CapType {
     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 {
@@ -118,7 +130,7 @@ impl CapEntry {
         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)
     }
 }
@@ -161,10 +173,10 @@ impl CapRegistry {
         }).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
         }

diff --git a/src/console.rs b/src/console.rs
line changes: +13/-5
index f089ba4..4a1c0b1
--- a/src/console.rs
+++ b/src/console.rs
@@ -1,5 +1,5 @@
-extern crate alloc;
 use core::cell::RefCell;
+use core::fmt::Write;
 
 use critical_section::Mutex;
 use usb_device::UsbError;
@@ -95,15 +95,23 @@ pub fn read(bytes: &mut [u8]) -> Result<usize, ConsoleError> {
     })
 }
 
-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)*));
     }}
 }
 

diff --git a/src/main.rs b/src/main.rs
line changes: +1/-3
index d8de592..dd2b282
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,8 @@
 #![no_std]
 #![no_main]
 #![feature(error_in_core)]
+#![feature(slice_internals)]
 
-mod allocator;
 mod apps;
 mod asm;
 mod capabilities;
@@ -17,7 +17,6 @@ mod timer;
 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};
@@ -37,7 +36,6 @@ fn main() -> ! {
         r0::init_data(&mut __skgram1, &mut __ekgram1, &mut __lkgram1);
     }
 
-    init_allocator();
     init_peripherals();
     init_console();
     init_tasks();

diff --git a/src/panic.rs b/src/panic.rs
line changes: +35/-53
index 3497f66..5a813b3
--- a/src/panic.rs
+++ b/src/panic.rs
@@ -1,72 +1,54 @@
+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 {}
+}

diff --git a/src/stdlib.rs b/src/stdlib.rs
line changes: +14/-0
index dba1c31..548f0d7
--- a/src/stdlib.rs
+++ b/src/stdlib.rs
@@ -42,4 +42,18 @@ pub fn read(buf: &mut [u8]) -> usize {
 
 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

diff --git a/src/svc.rs b/src/svc.rs
line changes: +19/-1
index 50c7025..086c82f
--- a/src/svc.rs
+++ b/src/svc.rs
@@ -76,7 +76,25 @@ unsafe fn svcall_handler(regs: Option<&mut TaskRegisters>) {
                 }
             });
         }
-        _ => (), //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"),
     }
 }
 

diff --git a/src/task.rs b/src/task.rs
line changes: +72/-8
index 1b33b8f..fb5e9b0
--- a/src/task.rs
+++ b/src/task.rs
@@ -3,7 +3,8 @@ mod error;
 
 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;
@@ -14,6 +15,7 @@ pub use error::TaskError;
 
 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};
 
@@ -87,7 +89,7 @@ impl TaskManager {
         regs.r1 = data_size;
 
         let t = TaskEntry {
-            id: 0,
+            id: tid,
             regs,
             data,
             data_size: data_size as usize,
@@ -130,31 +132,60 @@ impl TaskManager {
         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;
@@ -201,6 +232,8 @@ impl TaskManager {
             // 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();
@@ -210,6 +243,37 @@ impl TaskManager {
             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() {

diff --git a/src/task/entry.rs b/src/task/entry.rs
line changes: +15/-0
index f316d2e..1378cad
--- a/src/task/entry.rs
+++ b/src/task/entry.rs
@@ -1,3 +1,5 @@
+use core::fmt;
+
 use crate::capabilities::{CapToken, MAX_CAPS, CapType};
 use crate::task::TaskId;
 use crate::timer::Ticks;
@@ -12,6 +14,19 @@ pub enum TaskState {
     /// 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)]