From 478ed97beddd1d3107b252765df9bc82f83b38ee Mon Sep 17 00:00:00 2001 From: arthomnix Date: Wed, 29 Jan 2025 19:17:03 +0000 Subject: [PATCH] eepy: initial work on userspace USB interrupt handling --- eepy-sys/src/usb.rs | 18 +++++++++++- eepy/src/exception.rs | 30 ++++++++++++++++++++ eepy/src/main.rs | 19 +++++++++++-- eepy/src/syscall.rs | 37 ++++-------------------- eepy/src/usb.rs | 65 +++++++++++++++++++++++++++++++++++++++++++ eepy/src/usb.s | 25 +++++++++++++++++ 6 files changed, 158 insertions(+), 36 deletions(-) create mode 100644 eepy/src/exception.rs create mode 100644 eepy/src/usb.rs create mode 100644 eepy/src/usb.s diff --git a/eepy-sys/src/usb.rs b/eepy-sys/src/usb.rs index 0ffdd02..54f83ad 100644 --- a/eepy-sys/src/usb.rs +++ b/eepy-sys/src/usb.rs @@ -1 +1,17 @@ -// TODO \ No newline at end of file +#[repr(usize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum UsbSyscall { + UsbRet = 0, +} + +impl TryFrom for UsbSyscall { + type Error = (); + + fn try_from(value: usize) -> Result { + match value { + x if x == UsbSyscall::UsbRet as usize => Ok(UsbSyscall::UsbRet), + _ => Err(()), + } + } +} \ No newline at end of file diff --git a/eepy/src/exception.rs b/eepy/src/exception.rs new file mode 100644 index 0000000..2ecc0a8 --- /dev/null +++ b/eepy/src/exception.rs @@ -0,0 +1,30 @@ +use defmt::Formatter; + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub(crate) struct StackFrame { + pub r0: usize, + pub r1: usize, + pub r2: usize, + pub r3: usize, + pub r12: usize, + pub lr: *const u8, + pub pc: *const u8, + pub xpsr: usize, +} + +impl defmt::Format for StackFrame { + fn format(&self, fmt: Formatter) { + defmt::write!( + fmt, + "r0=0x{:x} r1=0x{:x} r2=0x{:x} r3=0x{:x} r12=0x{:x} lr={:x} pc={:x} xpsr=0x{:x}", + self.r0, + self.r1, + self.r2, + self.r3, + self.r12, + self.lr, + self.pc, + self.xpsr, + ) + } +} diff --git a/eepy/src/main.rs b/eepy/src/main.rs index ea0e68f..16fe5e5 100644 --- a/eepy/src/main.rs +++ b/eepy/src/main.rs @@ -5,6 +5,8 @@ mod serial; mod ringbuffer; mod syscall; mod launcher; +mod usb; +mod exception; extern crate panic_probe; extern crate defmt_rtt; @@ -235,7 +237,7 @@ fn main() -> ! { let mut timer = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks); // make sure temperature sensor has read temperature - timer.delay_ms(35); + //timer.delay_ms(35); let mut alarm = timer.alarm_0().unwrap(); alarm.enable_interrupt(); critical_section::with(|cs| GLOBAL_ALARM0.borrow_ref_mut(cs).replace(alarm)); @@ -278,7 +280,14 @@ fn main() -> ! { GLOBAL_USB_DEVICE = Some(usb_device); } - unsafe { pac::NVIC::unmask(interrupt::USBCTRL_IRQ) }; + unsafe { + core.NVIC.set_priority(interrupt::USBCTRL_IRQ, 0b11000000); + pac::NVIC::unmask(interrupt::USBCTRL_IRQ); + + // FIXME testing + core.NVIC.set_priority(interrupt::SW5_IRQ, 0b11000000); + pac::NVIC::unmask(interrupt::SW5_IRQ); + } let mut mc = Multicore::new(&mut pac.PSM, &mut pac.PPB, &mut sio.fifo); let core1 = &mut mc.cores()[1]; @@ -350,6 +359,7 @@ fn TIMER_IRQ_0() { trace!("TIMER_IRQ_0"); + if ALARM0.is_none() { critical_section::with(|cs| *ALARM0 = GLOBAL_ALARM0.borrow(cs).take()); } @@ -372,7 +382,7 @@ fn TIMER_IRQ_0() { TEMP.store(clamped, Ordering::Relaxed); alarm.clear_interrupt(); - alarm.schedule(1.minutes()).unwrap(); + alarm.schedule(1.secs()).unwrap(); } else { // I2C bus was in use, so try again in a short time alarm.clear_interrupt(); @@ -381,6 +391,9 @@ fn TIMER_IRQ_0() { } critical_section::with(|cs| GLOBAL_I2C.borrow(cs).replace(i2c)); + + // FIXME testing + pac::NVIC::pend(interrupt::SW5_IRQ); } #[interrupt] diff --git a/eepy/src/syscall.rs b/eepy/src/syscall.rs index 5e40010..ad81922 100644 --- a/eepy/src/syscall.rs +++ b/eepy/src/syscall.rs @@ -3,39 +3,11 @@ use defmt::{debug, trace, Formatter}; use eepy_sys::exec::exec; use eepy_sys::header::slot; use eepy_sys::syscall::SyscallNumber; +use crate::exception::StackFrame; use crate::SRAM_END; global_asm!(include_str!("syscall.s")); -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -struct StackFrame { - r0: usize, - r1: usize, - r2: usize, - r3: usize, - r12: usize, - lr: *const u8, - pc: *const u8, - xpsr: usize, -} - -impl defmt::Format for StackFrame { - fn format(&self, fmt: Formatter) { - defmt::write!( - fmt, - "r0=0x{:x} r1=0x{:x} r2=0x{:x} r3=0x{:x} r12=0x{:x} lr={:x} pc={:x} xpsr=0x{:x}", - self.r0, - self.r1, - self.r2, - self.r3, - self.r12, - self.lr, - self.pc, - self.xpsr, - ) - } -} - /// Main syscall (SVC) handler. /// /// This function is called by the assembly trampoline code in `syscall.s`. @@ -58,7 +30,7 @@ extern "C" fn handle_syscall(sp: *mut StackFrame, using_psp: bool) { Ok(SyscallNumber::Misc) => misc::handle_misc(stack_values), Ok(SyscallNumber::Image) => image::handle_image(stack_values), Ok(SyscallNumber::Input) => input::handle_input(stack_values), - Ok(SyscallNumber::Usb) => todo!("usb syscalls"), + Ok(SyscallNumber::Usb) => crate::usb::handle_usb(stack_values), Ok(SyscallNumber::Exec) => handle_exec(stack_values, using_psp), Err(_) => panic!("illegal syscall"), } @@ -81,7 +53,6 @@ fn handle_exec(stack_values: &mut StackFrame, using_psp: bool) { panic!("tried to exec invalid program"); } - (*program).load(); stack_values.pc = core::mem::transmute((*program).entry); stack_values.lr = program_return_handler as *const u8; @@ -102,11 +73,13 @@ fn handle_exec(stack_values: &mut StackFrame, using_psp: bool) { ptr = in(reg) SRAM_END, ) } + + (*program).load(); } } // NOTE: this function runs in unprivileged thread mode -extern "C" fn program_return_handler() { +extern "C" fn program_return_handler() -> ! { exec(0); } diff --git a/eepy/src/usb.rs b/eepy/src/usb.rs new file mode 100644 index 0000000..c224418 --- /dev/null +++ b/eepy/src/usb.rs @@ -0,0 +1,65 @@ +use core::arch::{asm, global_asm}; +use defmt::trace; +use eepy_sys::misc::get_serial; +use eepy_sys::usb::UsbSyscall; +use fw16_epd_bsp::pac; +use fw16_epd_bsp::pac::interrupt; +use crate::exception::StackFrame; + +global_asm!(include_str!("usb.s")); + +extern "C" { + fn usb_ret(); +} + +extern "C" fn example_usb_handler() { + // Do a syscall so it shows up in the kernel logs + // (we should be in unprivileged thread mode here so we can't use defmt) + core::hint::black_box(get_serial()); +} + +#[no_mangle] +extern "C" fn handle_usb_irq(sp: *mut StackFrame, using_psp: bool) { + trace!("fake USBCTRL_IRQ"); + + if !using_psp { + return; + } + + unsafe { + let new_sp = sp.sub(1); + new_sp.write(StackFrame { + r0: 0, + r1: 0, + r2: 0, + r3: 0, + r12: 0, + lr: usb_ret as *const u8, + pc: example_usb_handler as *const u8, + xpsr: 0x1000000, + }); + + asm!( + "msr psp, {new_psp}", + new_psp = in(reg) new_sp, + ); + } +} + +pub(crate) fn handle_usb(stack_values: &mut StackFrame) { + match UsbSyscall::try_from(stack_values.r0) { + Ok(UsbSyscall::UsbRet) => handle_usb_ret(stack_values), + Err(_) => {}, + } +} + +fn handle_usb_ret(stack_values: &mut StackFrame) { + trace!("usb_ret"); + unsafe { + let new_sp = (&raw mut *stack_values).add(1); + asm!( + "msr psp, {new_psp}", + new_psp = in(reg) new_sp, + ); + } +} \ No newline at end of file diff --git a/eepy/src/usb.s b/eepy/src/usb.s new file mode 100644 index 0000000..8a87479 --- /dev/null +++ b/eepy/src/usb.s @@ -0,0 +1,25 @@ +//.global USBCTRL_IRQ +.global SW5_IRQ + + .thumb_func +//USBCTRL_IRQ: +SW5_IRQ: + ldr r2, =handle_usb_irq + movs r0, #4 + mov r1, lr + tst r0, r1 + beq 100f // use_msp + mrs r0, psp + movs r1, #1 + bx r2 +100: // use_msp + mrs r0, msp + movs r1, #0 + bx r2 + +.global usb_ret + + .thumb_func +usb_ret: + movs r0, #0 + svc #3 \ No newline at end of file -- 2.51.2