From 5ffd12e49ac932d169ed0b36c423a680cfe55870 Mon Sep 17 00:00:00 2001 From: Kai Law Date: Mon, 2 Feb 2026 18:59:24 +0800 Subject: [PATCH 1/9] Add interrupt processing benchmarks --- adapter/thread_metric/BUILD.gn | 11 +++++++++++ adapter/thread_metric/src/lib.rs | 27 +++++++++++++++++++++++++++ kernel/src/arch/arm/mod.rs | 10 ++++++++++ 3 files changed, 48 insertions(+) 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..19128592 100644 --- a/adapter/thread_metric/src/lib.rs +++ b/adapter/thread_metric/src/lib.rs @@ -18,6 +18,7 @@ extern crate alloc; use alloc::alloc::{alloc as system_alloc, dealloc as system_dealloc}; use blueos::{ + arch::arm::{Context, NR_DEBUG_SYSCALL}, scheduler, scheduler::InsertToEnd, sync::semaphore::Semaphore, @@ -164,3 +165,29 @@ 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", + "ldr r7, ={nr}", + "svc 0", + "mov r7, {tmp}", + tmp = out(reg) _, + nr = const NR_DEBUG_SYSCALL, + options(nostack) + ) + } +} + +extern "C" { + fn tm_interrupt_handler(); +} + +#[no_mangle] +pub extern "C" fn bk_debug_syscall(ctx: &Context) -> usize { + let sp = ctx as *const _ as usize; + unsafe { tm_interrupt_handler() } + sp +} diff --git a/kernel/src/arch/arm/mod.rs b/kernel/src/arch/arm/mod.rs index b617fa3c..6fe45f71 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 - 1; pub const DISABLE_LOCAL_IRQ_BASEPRI: u8 = irq::IRQ_PRIORITY_FOR_SCHEDULER; #[macro_export] @@ -388,6 +389,12 @@ fn handle_svc_switch(ctx: &Context) -> usize { scheduler::save_context_finish_hook(&mut *hook, ctx as *const _ as usize) } +#[linkage = "weak"] +#[no_mangle] +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_SWITCH { return handle_svc_switch(ctx); @@ -397,6 +404,9 @@ extern "C" fn handle_syscall(ctx: &Context) -> usize { // return from syscall. ctx_before_syscall is contained in r0. return ctx.r0; } + if ctx.r7 == NR_DEBUG_SYSCALL { + return bk_debug_syscall(ctx); + } // Due to cortex-m's limitation, we split syscall handling into 2 phases: // P0: // Switch stack, go back to thread mode and run handler. Then syscalls From 4398fd4fc5dbf577663a35dbf8ea583e5c584558 Mon Sep 17 00:00:00 2001 From: Kai Law Date: Mon, 2 Feb 2026 19:58:06 +0800 Subject: [PATCH 2/9] Fix benchmark --- adapter/thread_metric/src/lib.rs | 18 ++++++++++-------- kernel/src/arch/arm/mod.rs | 10 +++++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/adapter/thread_metric/src/lib.rs b/adapter/thread_metric/src/lib.rs index 19128592..a4e31b05 100644 --- a/adapter/thread_metric/src/lib.rs +++ b/adapter/thread_metric/src/lib.rs @@ -13,12 +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::{Context, NR_DEBUG_SYSCALL}, + arch::arm::{self, Context, NR_DEBUG_SYSCALL}, scheduler, scheduler::InsertToEnd, sync::semaphore::Semaphore, @@ -85,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 @@ -171,7 +174,7 @@ pub extern "C" fn tm_cause_interrupt() { unsafe { core::arch::asm!( "movs {tmp}, r7", - "ldr r7, ={nr}", + "mov r7, #{nr}", "svc 0", "mov r7, {tmp}", tmp = out(reg) _, @@ -181,13 +184,12 @@ pub extern "C" fn tm_cause_interrupt() { } } -extern "C" { - fn tm_interrupt_handler(); -} +#[no_mangle] +#[linkage = "weak"] +pub extern "C" fn tm_interrupt_handler() {} #[no_mangle] pub extern "C" fn bk_debug_syscall(ctx: &Context) -> usize { - let sp = ctx as *const _ as usize; unsafe { tm_interrupt_handler() } - sp + ctx as *const _ as usize } diff --git a/kernel/src/arch/arm/mod.rs b/kernel/src/arch/arm/mod.rs index 6fe45f71..13f441d4 100644 --- a/kernel/src/arch/arm/mod.rs +++ b/kernel/src/arch/arm/mod.rs @@ -317,7 +317,7 @@ macro_rules! load_callee_saved_regs { 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] @@ -389,13 +389,16 @@ fn handle_svc_switch(ctx: &Context) -> usize { scheduler::save_context_finish_hook(&mut *hook, ctx as *const _ as usize) } -#[linkage = "weak"] #[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); } @@ -404,9 +407,6 @@ extern "C" fn handle_syscall(ctx: &Context) -> usize { // return from syscall. ctx_before_syscall is contained in r0. return ctx.r0; } - if ctx.r7 == NR_DEBUG_SYSCALL { - return bk_debug_syscall(ctx); - } // Due to cortex-m's limitation, we split syscall handling into 2 phases: // P0: // Switch stack, go back to thread mode and run handler. Then syscalls From 57a8f79ae8b563b6cc9babceb750f7c3641fc85a Mon Sep 17 00:00:00 2001 From: Kai Law Date: Mon, 2 Feb 2026 20:04:57 +0800 Subject: [PATCH 3/9] Fix check_all --- .../tests/tm_interrupt_preemption_processing_test.checker | 3 +++ .../thread_metric/tests/tm_interrupt_processing_test.checker | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 adapter/thread_metric/tests/tm_interrupt_preemption_processing_test.checker create mode 100644 adapter/thread_metric/tests/tm_interrupt_processing_test.checker 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 From 115679683b60664a149a5a58162c5edd47a0aa05 Mon Sep 17 00:00:00 2001 From: Kai Law Date: Mon, 2 Feb 2026 21:45:22 +0800 Subject: [PATCH 4/9] Fix NR --- kernel/src/arch/arm/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/src/arch/arm/mod.rs b/kernel/src/arch/arm/mod.rs index 13f441d4..e3b617e3 100644 --- a/kernel/src/arch/arm/mod.rs +++ b/kernel/src/arch/arm/mod.rs @@ -40,7 +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 - 1; +pub const NR_DEBUG_SYSCALL: usize = NR_SWITCH - 2; pub const DISABLE_LOCAL_IRQ_BASEPRI: u8 = irq::IRQ_PRIORITY_FOR_SCHEDULER; #[macro_export] From 556c5c3284758acbbab726111c3e5e4afa17ab00 Mon Sep 17 00:00:00 2001 From: Kai Law Date: Mon, 2 Feb 2026 21:52:23 +0800 Subject: [PATCH 5/9] Remove unsafe --- adapter/thread_metric/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapter/thread_metric/src/lib.rs b/adapter/thread_metric/src/lib.rs index a4e31b05..f64e826b 100644 --- a/adapter/thread_metric/src/lib.rs +++ b/adapter/thread_metric/src/lib.rs @@ -190,6 +190,6 @@ pub extern "C" fn tm_interrupt_handler() {} #[no_mangle] pub extern "C" fn bk_debug_syscall(ctx: &Context) -> usize { - unsafe { tm_interrupt_handler() } + tm_interrupt_handler(); ctx as *const _ as usize } From 9ea0ef6c207ab5ea015217885f986b95cf5cf3e2 Mon Sep 17 00:00:00 2001 From: Kai Law Date: Mon, 2 Feb 2026 21:59:12 +0800 Subject: [PATCH 6/9] Improve minor --- kernel/src/scheduler/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel/src/scheduler/mod.rs b/kernel/src/scheduler/mod.rs index 6f405817..0ec37271 100644 --- a/kernel/src/scheduler/mod.rs +++ b/kernel/src/scheduler/mod.rs @@ -251,13 +251,13 @@ pub(crate) extern "C" fn relinquish_me_and_return_next_sp(old_sp: usize) -> usiz 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(); + 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 +265,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) } From eec325f45d7e758c10d40ae98adf5dee6ad4dac2 Mon Sep 17 00:00:00 2001 From: Kai Law Date: Mon, 2 Feb 2026 22:06:51 +0800 Subject: [PATCH 7/9] Add inline hint --- kernel/src/arch/arm/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/src/arch/arm/mod.rs b/kernel/src/arch/arm/mod.rs index e3b617e3..4dbcd93b 100644 --- a/kernel/src/arch/arm/mod.rs +++ b/kernel/src/arch/arm/mod.rs @@ -315,6 +315,7 @@ macro_rules! load_callee_saved_regs { }; } +#[inline(always)] pub(crate) extern "C" fn post_pendsv() { SCB::set_pendsv(); unsafe { core::arch::asm!("isb", options(nostack),) } From b0355a5ee8fc17025bbeae25f3ca1d612c1ffa3c Mon Sep 17 00:00:00 2001 From: Kai Law Date: Mon, 2 Feb 2026 22:45:50 +0800 Subject: [PATCH 8/9] Fix isb placement --- kernel/src/arch/arm/mod.rs | 7 ++++--- kernel/src/scheduler/mod.rs | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/kernel/src/arch/arm/mod.rs b/kernel/src/arch/arm/mod.rs index 4dbcd93b..aa60495f 100644 --- a/kernel/src/arch/arm/mod.rs +++ b/kernel/src/arch/arm/mod.rs @@ -98,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} ", @@ -328,6 +327,7 @@ pub unsafe extern "C" fn handle_svc() { " ldr r12, ={basepri} msr basepri, r12 + isb ", store_callee_saved_regs!(), " @@ -341,7 +341,6 @@ pub unsafe extern "C" fn handle_svc() { " ldr r12, =0 msr basepri, r12 - isb bx lr ", ), @@ -445,6 +444,7 @@ pub unsafe extern "C" fn handle_pendsv() { " ldr r12, ={basepri} msr basepri, r12 + isb ", store_callee_saved_regs!(), " @@ -458,7 +458,6 @@ pub unsafe extern "C" fn handle_pendsv() { " ldr r12, =0 msr basepri, r12 - isb bx lr " ), @@ -525,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), ) @@ -541,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 0ec37271..acf7aad3 100644 --- a/kernel/src/scheduler/mod.rs +++ b/kernel/src/scheduler/mod.rs @@ -248,10 +248,11 @@ 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 % 8, 0); debug_assert!(!arch::local_irq_enabled()); debug_assert!(!crate::irq::is_in_irq()); - debug_assert_eq!(current_thread_ref().preempt_count(), 0); 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", Thread::id(old)); @@ -283,14 +284,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 _); From 3248383eae9d51f7cfe2cb112262a9f84f0385e7 Mon Sep 17 00:00:00 2001 From: Kai Law Date: Tue, 3 Feb 2026 14:00:39 +0800 Subject: [PATCH 9/9] Add alignment check --- kernel/src/scheduler/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/src/scheduler/mod.rs b/kernel/src/scheduler/mod.rs index acf7aad3..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,7 +249,7 @@ 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 % 8, 0); + debug_assert_eq!(old_sp % core::mem::align_of::(), 0); debug_assert!(!arch::local_irq_enabled()); debug_assert!(!crate::irq::is_in_irq()); let old = current_thread_ref();