use core::arch::naked_asm;
use core::fmt;
use memory_addr::VirtAddr;
#[repr(C)]
#[derive(Default, Clone, Copy)]
pub struct TrapFrame {
pub r: [u32; 13],
pub sp: u32,
pub lr: u32,
pub pc: u32,
pub cpsr: u32,
}
impl fmt::Debug for TrapFrame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "TrapFrame: {{")?;
for (i, ®) in self.r.iter().enumerate() {
writeln!(f, " r{i}: {reg:#x},")?;
}
writeln!(f, " sp: {:#x},", self.sp)?;
writeln!(f, " lr: {:#x},", self.lr)?;
writeln!(f, " pc: {:#x},", self.pc)?;
writeln!(f, " cpsr: {:#x},", self.cpsr)?;
write!(f, "}}")?;
Ok(())
}
}
impl TrapFrame {
pub const fn arg0(&self) -> usize {
self.r[0] as _
}
pub const fn arg1(&self) -> usize {
self.r[1] as _
}
pub const fn arg2(&self) -> usize {
self.r[2] as _
}
pub const fn arg3(&self) -> usize {
self.r[3] as _
}
pub const fn arg4(&self) -> usize {
self.r[4] as _
}
pub const fn arg5(&self) -> usize {
self.r[5] as _
}
}
#[repr(C, align(16))]
#[derive(Debug, Default)]
pub struct FpState {
pub regs: [u64; 32],
pub fpscr: u32,
}
#[cfg(feature = "fp-simd")]
impl FpState {
pub fn save(&mut self) {
unsafe { fpstate_save(self) }
}
pub fn restore(&self) {
unsafe { fpstate_restore(self) }
}
}
#[allow(missing_docs)]
#[repr(C)]
#[derive(Debug, Default)]
pub struct TaskContext {
pub sp: u32,
pub r4: u32,
pub r5: u32,
pub r6: u32,
pub r7: u32,
pub r8: u32,
pub r9: u32,
pub r10: u32,
pub r11: u32,
pub lr: u32, #[cfg(feature = "tls")]
pub tp: u32,
#[cfg(feature = "fp-simd")]
pub fp_state: FpState,
}
impl TaskContext {
pub fn new() -> Self {
Self::default()
}
pub fn init(&mut self, entry: usize, kstack_top: VirtAddr, tls_area: VirtAddr) {
self.sp = kstack_top.as_usize() as u32;
self.lr = entry as u32;
#[cfg(feature = "tls")]
{
self.tp = tls_area.as_usize() as u32;
}
#[cfg(not(feature = "tls"))]
let _ = tls_area;
}
pub fn switch_to(&mut self, next_ctx: &Self) {
#[cfg(feature = "tls")]
{
self.tp = crate::asm::read_thread_pointer() as u32;
unsafe { crate::asm::write_thread_pointer(next_ctx.tp as usize) };
}
#[cfg(feature = "fp-simd")]
{
self.fp_state.save();
next_ctx.fp_state.restore();
}
unsafe { context_switch(self, next_ctx) }
}
}
#[cfg(feature = "fp-simd")]
#[unsafe(naked)]
unsafe extern "C" fn fpstate_save(_fp_state: &mut FpState) {
naked_asm!(
"
vstm r0!, {{d0-d15}}
vstm r0!, {{d16-d31}}
vmrs r1, fpscr
str r1, [r0]
bx lr"
)
}
#[cfg(feature = "fp-simd")]
#[unsafe(naked)]
unsafe extern "C" fn fpstate_restore(_fp_state: &FpState) {
naked_asm!(
"
vldm r0!, {{d0-d15}}
vldm r0!, {{d16-d31}}
ldr r1, [r0]
vmsr fpscr, r1
bx lr"
)
}
#[unsafe(naked)]
unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task: &TaskContext) {
naked_asm!(
"
// save old context (callee-saved registers)
str lr, [r0, #9*4]
str r11, [r0, #8*4]
str r10, [r0, #7*4]
str r9, [r0, #6*4]
str r8, [r0, #5*4]
str r7, [r0, #4*4]
str r6, [r0, #3*4]
str r5, [r0, #2*4]
str r4, [r0, #1*4]
str sp, [r0, #0*4]
// restore new context
ldr sp, [r1, #0*4]
ldr r4, [r1, #1*4]
ldr r5, [r1, #2*4]
ldr r6, [r1, #3*4]
ldr r7, [r1, #4*4]
ldr r8, [r1, #5*4]
ldr r9, [r1, #6*4]
ldr r10, [r1, #7*4]
ldr r11, [r1, #8*4]
ldr lr, [r1, #9*4]
bx lr",
)
}