/src/svc.rs
use core::arch::global_asm;
use embedded_hal::digital::v2::OutputPin;
use usbd_hid::descriptor::KeyboardReport;
use crate::bsp::pac::SCB;
use crate::capabilities::CapType;
use crate::console::{self, ConsoleError};
use crate::kprintf;
use crate::peripherals::{with_peripherals, with_usb};
use crate::task::{current_task_has_capability, with_task_manager, TaskRegisters};
use crate::timer::ticks;
global_asm!(
r#"
.global SVCall
.type SVCall,function
SVCall:
ExceptionEntry
bl svcall_handler // call the handler
ExceptionExit
"#
);
#[no_mangle]
unsafe fn svcall_handler(regs: Option<&mut TaskRegisters>) {
let regs = regs.expect("SVCall in kernel mode!?");
match regs.r0 {
1 => {
with_task_manager(|tm| {
tm.sleep(regs.r1);
SCB::set_pendsv();
});
}
2 => {
if !current_task_has_capability(CapType::ConsoleWrite) {
return;
}
let bytes = core::slice::from_raw_parts(regs.r1 as *const u8, regs.r2 as usize);
match console::write(bytes) {
Ok(n) => regs.r0 = n as u32,
Err(ConsoleError::Blocked) => {
with_task_manager(|tm| tm.block_current_task(CapType::ConsoleWrite));
SCB::set_pendsv();
}
Err(e) => panic!("write syscall error: {:?}", e),
}
}
3 => {
if !current_task_has_capability(CapType::ConsoleRead) {
return;
}
let bytes = core::slice::from_raw_parts_mut(regs.r1 as *mut u8, regs.r2 as usize);
match console::read(bytes) {
Ok(n) => regs.r0 = n as u32,
Err(ConsoleError::Blocked) => {
with_task_manager(|t| {
t.block_current_task(CapType::ConsoleRead);
SCB::set_pendsv();
});
}
Err(e) => panic!("read syscall error: {:?}", e),
}
}
4 => {
if !current_task_has_capability(CapType::Led) {
return;
}
let on = regs.r1 != 0;
with_peripherals(|p| {
if on {
p.led().set_high().ok()
} else {
p.led().set_low().ok()
}
});
}
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("TODO", entry, &[], 10));
match r {
Ok(tid) => regs.r0 = tid,
Err(_) => regs.r0 = 0xFFFFFFFF,
}
}
102 => {
with_task_manager(|tm| tm.print_tasks());
}
200 => {
let p = 0x4000 as *const u8;
let b = *p;
regs.r0 = b as u32;
}
1000 => {
// kb_read_matrix(bits: *mut u32)
if !current_task_has_capability(CapType::Keyboard) {
return;
}
let keys = core::slice::from_raw_parts_mut(regs.r1 as *mut u32, 3);
let keybits = with_peripherals(|p| p.keyboard().scan());
keys.copy_from_slice(&keybits);
}
1001 => {
// kb_write_hid(arr: *const u8, len: usize) -> bool
if !current_task_has_capability(CapType::Keyboard) {
return;
}
if regs.r2 > 8 {
return;
}
let raw_report = core::slice::from_raw_parts(regs.r1 as *const u8, regs.r2 as usize);
let report = KeyboardReport {
modifier: raw_report[0],
reserved: 0,
leds: 0,
keycodes: raw_report[2..].try_into().unwrap(),
};
let r = with_usb(|u| u.keyboard().push_input(&report));
regs.r0 = match r {
Ok(_) => 1,
Err(e) => {
kprintf!("{:?}\r\n", e);
0
}
};
}
_ => panic!("Unknown SVCall"),
}
}
global_asm!(
r#"
.global PendSV
.type PendSV,function
PendSV:
ExceptionEntry
bl pendsv_handler // call the handler
ExceptionExit
"#
);
#[no_mangle]
unsafe fn pendsv_handler(regs: Option<&mut TaskRegisters>) {
let Some(regs) = regs else {
// If we wind up here from handler mode; just bail. This should
// only happen during debugging.
return;
};
let t = ticks();
with_task_manager(|tm| {
tm.schedule(t);
tm.task_swap(regs);
});
SCB::clear_pendsv();
}