diff --git a/adapter/thread_metric/BUILD.gn b/adapter/thread_metric/BUILD.gn index a2d617b7..6db9e85f 100644 --- a/adapter/thread_metric/BUILD.gn +++ b/adapter/thread_metric/BUILD.gn @@ -56,10 +56,21 @@ tm_case("tm_memory_allocation_test") { [ "//external/thread_metric/v6.4.2/src/tm_memory_allocation_test.c" ] } +tm_case("tm_interrupt_preemption_processing_test") { + sources = [ "//external/thread_metric/v6.4.2/src/tm_interrupt_preemption_processing_test.c" ] +} + +tm_case("tm_interrupt_processing_test") { + sources = + [ "//external/thread_metric/v6.4.2/src/tm_interrupt_processing_test.c" ] +} + group("run_tests") { testonly = true deps = [ ":run_tm_basic_process_test", + ":run_tm_interrupt_preemption_processing_test", + ":run_tm_interrupt_processing_test", ":run_tm_memory_allocation_test", ":run_tm_preemptive_scheduling_test", ":run_tm_synchronization_processing_test", diff --git a/adapter/thread_metric/src/lib.rs b/adapter/thread_metric/src/lib.rs index 7ebdc23b..f64e826b 100644 --- a/adapter/thread_metric/src/lib.rs +++ b/adapter/thread_metric/src/lib.rs @@ -13,11 +13,15 @@ // limitations under the License. #![no_std] +#![feature(linkage)] + +extern crate blueos; extern crate alloc; use alloc::alloc::{alloc as system_alloc, dealloc as system_dealloc}; use blueos::{ + arch::arm::{self, Context, NR_DEBUG_SYSCALL}, scheduler, scheduler::InsertToEnd, sync::semaphore::Semaphore, @@ -84,7 +88,7 @@ pub extern "C" fn tm_thread_resume(thread_id: c_int) -> c_int { if scheduler::queue_ready_thread(SUSPENDED, t.clone()).is_ok() || scheduler::queue_ready_thread(IDLE, t).is_ok() { - scheduler::relinquish_me(); + scheduler::yield_me_now_or_later(); return TM_SUCCESS; } TM_ERROR @@ -164,3 +168,28 @@ pub extern "C" fn tm_memory_pool_deallocate(_pool_id: c_int, result: *mut u8) -> unsafe { system_dealloc(result, layout) }; TM_SUCCESS } + +#[no_mangle] +pub extern "C" fn tm_cause_interrupt() { + unsafe { + core::arch::asm!( + "movs {tmp}, r7", + "mov r7, #{nr}", + "svc 0", + "mov r7, {tmp}", + tmp = out(reg) _, + nr = const NR_DEBUG_SYSCALL, + options(nostack) + ) + } +} + +#[no_mangle] +#[linkage = "weak"] +pub extern "C" fn tm_interrupt_handler() {} + +#[no_mangle] +pub extern "C" fn bk_debug_syscall(ctx: &Context) -> usize { + tm_interrupt_handler(); + ctx as *const _ as usize +} diff --git a/adapter/thread_metric/tests/tm_interrupt_preemption_processing_test.checker b/adapter/thread_metric/tests/tm_interrupt_preemption_processing_test.checker new file mode 100644 index 00000000..30a4207b --- /dev/null +++ b/adapter/thread_metric/tests/tm_interrupt_preemption_processing_test.checker @@ -0,0 +1,3 @@ +// TOTAL-TIMEOUT: 10 +// ASSERT-SUCC: Relative Time: 8 +// ASSERT-FAIL: ERROR \ No newline at end of file diff --git a/adapter/thread_metric/tests/tm_interrupt_processing_test.checker b/adapter/thread_metric/tests/tm_interrupt_processing_test.checker new file mode 100644 index 00000000..30a4207b --- /dev/null +++ b/adapter/thread_metric/tests/tm_interrupt_processing_test.checker @@ -0,0 +1,3 @@ +// TOTAL-TIMEOUT: 10 +// ASSERT-SUCC: Relative Time: 8 +// ASSERT-FAIL: ERROR \ No newline at end of file diff --git a/kernel/src/arch/arm/mod.rs b/kernel/src/arch/arm/mod.rs index b617fa3c..aa60495f 100644 --- a/kernel/src/arch/arm/mod.rs +++ b/kernel/src/arch/arm/mod.rs @@ -40,6 +40,7 @@ pub const CONTROL: usize = 0b110; pub const THUMB_MODE: usize = 0x01000000; pub const NR_SWITCH: usize = !0; pub const NR_RET_FROM_SYSCALL: usize = NR_SWITCH - 1; +pub const NR_DEBUG_SYSCALL: usize = NR_SWITCH - 2; pub const DISABLE_LOCAL_IRQ_BASEPRI: u8 = irq::IRQ_PRIORITY_FOR_SCHEDULER; #[macro_export] @@ -97,7 +98,6 @@ pub extern "C" fn reset_msp_and_start_schedule(msp: *mut u8, cont: extern "C" fn msr control, {tmp} ldr lr, =0 msr basepri, {basepri} - isb cpsie i bx {cont} ", @@ -314,9 +314,10 @@ macro_rules! load_callee_saved_regs { }; } +#[inline(always)] pub(crate) extern "C" fn post_pendsv() { SCB::set_pendsv(); - unsafe { core::arch::asm!("dsb", "isb", options(nostack),) } + unsafe { core::arch::asm!("isb", options(nostack),) } } #[naked] @@ -326,6 +327,7 @@ pub unsafe extern "C" fn handle_svc() { " ldr r12, ={basepri} msr basepri, r12 + isb ", store_callee_saved_regs!(), " @@ -339,7 +341,6 @@ pub unsafe extern "C" fn handle_svc() { " ldr r12, =0 msr basepri, r12 - isb bx lr ", ), @@ -388,7 +389,16 @@ fn handle_svc_switch(ctx: &Context) -> usize { scheduler::save_context_finish_hook(&mut *hook, ctx as *const _ as usize) } +#[no_mangle] +#[linkage = "weak"] +pub extern "C" fn bk_debug_syscall(ctx: &Context) -> usize { + ctx as *const _ as usize +} + extern "C" fn handle_syscall(ctx: &Context) -> usize { + if ctx.r7 == NR_DEBUG_SYSCALL { + return bk_debug_syscall(ctx); + } if ctx.r7 == NR_SWITCH { return handle_svc_switch(ctx); } @@ -434,6 +444,7 @@ pub unsafe extern "C" fn handle_pendsv() { " ldr r12, ={basepri} msr basepri, r12 + isb ", store_callee_saved_regs!(), " @@ -447,7 +458,6 @@ pub unsafe extern "C" fn handle_pendsv() { " ldr r12, =0 msr basepri, r12 - isb bx lr " ), @@ -514,6 +524,7 @@ pub extern "C" fn disable_local_irq() { unsafe { core::arch::asm!( "msr basepri, {}", + "isb", in(reg) DISABLE_LOCAL_IRQ_BASEPRI, options(nostack), ) @@ -530,6 +541,7 @@ pub extern "C" fn disable_local_irq_save() -> usize { " mrs {old}, basepri msr basepri, {val} + isb ", ), old = out(reg) old, diff --git a/kernel/src/scheduler/mod.rs b/kernel/src/scheduler/mod.rs index 6f405817..1db34911 100644 --- a/kernel/src/scheduler/mod.rs +++ b/kernel/src/scheduler/mod.rs @@ -14,7 +14,8 @@ extern crate alloc; use crate::{ - arch, signal, + arch::{self, Context}, + signal, support::DisableInterruptGuard, sync::SpinLockGuard, thread, @@ -248,16 +249,17 @@ fn switch_current_thread(next: ThreadNode, old_sp: usize) -> usize { // It's usually used in cortex-m's pendsv handler. pub(crate) extern "C" fn relinquish_me_and_return_next_sp(old_sp: usize) -> usize { + debug_assert_eq!(old_sp % core::mem::align_of::(), 0); debug_assert!(!arch::local_irq_enabled()); debug_assert!(!crate::irq::is_in_irq()); - debug_assert_eq!(current_thread_ref().preempt_count(), 0); - let Some(next) = next_preferred_thread(current_thread_ref().priority()) else { + let old = current_thread_ref(); + debug_assert_eq!(old.preempt_count(), 0); + let Some(next) = next_preferred_thread(old.priority()) else { #[cfg(debugging_scheduler)] - crate::trace!("[TH:0x{:x}] keeps running", current_thread_id()); + crate::trace!("[TH:0x{:x}] keeps running", Thread::id(old)); return old_sp; }; debug_assert_eq!(next.state(), thread::READY); - let old = current_thread_ref(); if Thread::id(old) == Thread::id(idle::current_idle_thread_ref()) { let ok = old.transfer_state(thread::RUNNING, thread::READY); debug_assert_eq!(ok, Ok(())); @@ -265,7 +267,6 @@ pub(crate) extern "C" fn relinquish_me_and_return_next_sp(old_sp: usize) -> usiz let ok = queue_ready_thread(thread::RUNNING, unsafe { Arc::clone_from(old) }); debug_assert_eq!(ok, Ok(())); }; - switch_current_thread(next, old_sp) } @@ -284,14 +285,14 @@ pub fn retire_me() -> ! { } fn inner_yield(next: ThreadNode) { - let old = current_thread(); + let old = current_thread_ref(); let mut hook_holder = ContextSwitchHookHolder::new(next); old.disable_preempt(); - if Thread::id(&old) == Thread::id(idle::current_idle_thread_ref()) { + if Thread::id(old) == Thread::id(idle::current_idle_thread_ref()) { let ok = old.transfer_state(thread::RUNNING, thread::READY); debug_assert_eq!(ok, Ok(())); } else { - let ok = queue_ready_thread(thread::RUNNING, old.clone()); + let ok = queue_ready_thread(thread::RUNNING, unsafe { Arc::clone_from(old) }); debug_assert_eq!(ok, Ok(())); }; arch::switch_context_with_hook(&mut hook_holder as *mut _);