/src/task.rs
use core::ptr;
use crate::mpu::{self, MemoryRegion, MemoryPermission, MemoryRange};
extern "C" {
static _appram: u32;
static _appram_end: u32;
pub fn launch(entry: u32, sp: u32, data_base: u32) -> !;
}
global_asm!(r#"
.global launch
.type launch,function
launch:
// Move entry address out of the way
mov r3, r0
// set up PSP and drop privileges
mov r0, 0x3
msr CONTROL, r0
// set stack pointer and pointer to data region info
mov sp, r1
mov r0, r1
// set up memory region pointer
mov r9, r2
isb
dsb
bx r3
"#);
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct Task {
text: MemoryRegion,
data: MemoryRegion,
stack: MemoryRegion,
pc: u32,
sp: u32,
}
impl Task {
pub fn default_layout_full(entry: unsafe extern "C" fn() -> u32) -> Task {
let appram_base = unsafe { &_appram as *const u32 as u32 };
let stack_start = appram_base + 0x10000 + 0xe000;
let stack_size = 0x2000;
let stack_end = stack_start + stack_size;
Task {
text: MemoryRegion {
start: 0x00000000,
length: 0,
permissions: MemoryPermission::None,
xn: false,
},
data: MemoryRegion {
start: appram_base,
length: 0x10000,
permissions: MemoryPermission::RW,
xn: true,
},
stack: MemoryRegion {
start: stack_start,
length: stack_size,
permissions: MemoryPermission::RW,
xn: true,
},
pc: entry as *const () as u32,
sp: stack_end,
}
}
pub fn run(&self) -> ! {
mpu::add_region(&self.text);
mpu::add_region(&self.data);
mpu::add_region(&self.stack);
unsafe {
let sp = self.sp as *mut MemoryRange;
let sp = sp.sub(1);
ptr::write(sp, MemoryRange {
start: self.data.start,
length: self.data.length - self.stack.length,
});
let sp = sp as u32;
launch(self.pc, sp, self.data.start)
}
}
}