1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//! Scheduler.

/// Scheduler.
///
/// # Implementation
/// In addition to the trait the hardware context switch exception must be
/// implemented. The exception must
/// 1. Push the CPU registers to the stack
/// 2. Call `switch_context` from the kernel
///     - in: current task stack pointer in first parameter register (e.g. `r0`)
///     - out: next task stack pointer in return register (e.g. `r0`)
/// 3. Pop CPU register from new stack
///
/// On a ARM Cortex-M4 for example (simplified):
/// ```ignore
/// #[no_mangle]
/// #[naked]
/// extern "C" fn PendSV() {
///     unsafe {
///         asm!(
///         "push    {{lr}}",
///         "mrs     r0, psp",         // get process stack pointer
///         "stmdb   r0!, {{r4-r11}}", // push registers to stack A
///         "bl      switch_context",  // call kernel for context switch
///         "pop     {{lr}}",
///         "mov     r3, #3",
///         "msr     control, r3",      // run in unprivileged mode
///         "isb",
///         "ldmia   r0!, {{r4-r11}}",  // pop registers from stack B
///         "msr     psp, r0",          // set process stack pointer
///         "bx      lr",
///         options(noreturn),
///         )
///     }
/// }
/// ```
///
/// The exception can call `check_stack` to check wheter the there is enough
/// space left to store the registers.
///     - in: stack pointer after stacking
///     - out: 0 - stack would overflow, 1 - enought space left
pub trait IScheduler {
    /// Init the stack of task.
    ///
    /// # Safety
    /// The stack must be large enough for the initial stack frame.
    unsafe fn init_task_stack(stack_ptr: *mut usize, entry: *const usize, arg: *const usize, exit: *const usize) -> *mut usize;
    /// Start the first task.
    fn start_first_task(stack_ptr: *const usize) -> !;
    /// Trigger context switch exception.
    fn trigger_context_switch();
}