gpio_toggle()과 sleep_ms()에서 syscall을 호출할 때, 실제로 svc_call()을 통해 SVC 핸들러 (svcall_rust)에 도달하고 있는가?
extern "C" fn svcall_rust(frame: &mut ExceptionFrame) {
let call_id = (frame.r0 & 0xFF) as u8;
rprintln!("[SVC] svcall_rust called with ID: {}", call_id);
SVC_COUNTER.fetch_add(1, Ordering::Relaxed);
if call_id == abi::NOW_MS {
NOW_COUNT.fetch_add(1, Ordering::Relaxed);
}
let ret = unsafe {
kernel_dispatch(call_id, frame.r1, frame.r2, frame.r3, frame.r12)
};
frame.r0 = ret;
}
실행 결과, SVC call은 잘 되지만, 다음 task가 돌아가지 않았다. 즉, 한 번만 호출된 것.
Terminal
[mini-os] Booting
11:35:31.961: p0=0x200007F8 p1=0x20000BF8 p2=0x20000FF8
11:35:31.961: Starting scheduler...
11:35:31.961: [SVC] svcall_rust called with ID: 3
이를 통해 예측할 수 있는 오류 원인은
첫 Task 실행 후 Context Switch가 일어나지 않았다.
그러면 이제 SysTick()에서 interrupt가 잘 발생하고 있는지 확인해보자.
#[exception]
fn SysTick() {
rprintln!("[SysTick] interrupt fired");
unsafe { core::ptr::write_volatile(ICSR, 1 << 28); }
}
실행 결과, rtt가 무한으로 찍히고 있었다.
-> 일단 SysTick()은 잘 호출되고 있었다. 즉, init_systick_50us()에서 설정한 SysTick 타이머가 정상적으로 작동한다는 것이다
-> 따라서 원인을 더욱 좁혀보자면
PendSV 핸들러가 실행되지 않는다!