Tock OS 구현기 2

Nitroblue 1·2025년 9월 15일

Tiered Trust implementation

  • Board(core kernel) : unsafe 허용, 레지스터 직접 접근.
  • Capsules(drivers virtualization layer) : unsafe 금지. privileged object를 safe API로만 사용할 예정.
  • Apps(사용자 앱) : OS가 주는 Syscalls만 사용(지금은 커널 내부에서 돌지만, 인터페이스는 그대로 유지)

Schedular 구현중.

mod sched {
    use core::arch::global_asm;

    use cortex_m_rt::exception;

    pub const N_TASKS: usize = 3;
    const STACK_WORDS: usize = 256; // 1KB stack per task

    #[repr(C)]
    #[derive(Copy, Clone)]
    pub struct Tcb {
        pub sp: u32,    // Process SP for this task
    }

    // Task table (PSP contexts) and stacks
    pub static mut TCBS: [Tcb; N_TASKS] = [Tcb { sp: 0 }; N_TASKS];
    
    #[repr(align(8))]
    #[derive(Copy, Clone)]
    struct Stack8([u32; STACK_WORDS]);
    static mut STACKS: [Stack8; N_TASKS] = [Stack8([0; STACK_WORDS]); N_TASKS];
    pub static mut CURR: usize = 0;

     // Addresses for SCB registers (for priority+PendSV trigger)
    const ICSR: *mut u32  = 0xE000_ED04 as *mut u32; // bit28 = PENDSVSET
    const SHPR3:*mut u32  = 0xE000_ED20 as *mut u32; // [31:24]=SysTick, [23:16]=PendSV

    unsafe extern "C" {
    fn task0_entry() -> !;
    fn task1_entry() -> !;
    fn task2_entry() -> !;
    }

    #[inline(always)]
    fn build_initial_psp(stack: &mut [u32], entry_addr: u32) -> u32 {
        let total_words = 8 + 8; let len = stack.len(); let base = len - total_words;
        for i in 0..8 { stack[base + i] = 0; } // r4-r11
        // 하드웨어 프레임 (R0..R3, R12, LR, PC, xPSR)
        stack[base + 8 + 0] = 0;                        // R0
        stack[base + 8 + 1] = 0;                        // R1
        stack[base + 8 + 2] = 0;                        // R2
        stack[base + 8 + 3] = 0;                        // R3
        stack[base + 8 + 4] = 0;                        // R12
        stack[base + 8 + 5] = task_return_trap as u32;  // LR
        stack[base + 8 + 6] = entry_addr as u32;        // PC
        stack[base + 8 + 7] = 0x0100_0000;              // xPSR (T-bit)
        (stack.as_ptr().wrapping_add(base)) as usize as u32
    }

    extern "C" fn task_return_trap() -> ! {
        loop {
            unsafe {
                core::ptr::write_volatile(ICSR, 1 << 28);
            }
            cortex_m::asm::bkpt();
        }
    }

    pub unsafe fn init_systick_50us() {
        let mut v = unsafe { core::ptr::read_volatile(SHPR3) };
        v &= !0xFFFF_0000;
        v |= (0x80u32 << 24) | (0xFFu32 << 16);
        unsafe { core::ptr::write_volatile(SHPR3, v) };

        let syst_csr  = 0xE000_E010 as *mut u32;
        let syst_rvr  = 0xE000_E014 as *mut u32;
        let syst_cvr  = 0xE000_E018 as *mut u32;

        unsafe { core::ptr::write_volatile(syst_rvr, 799) };
        unsafe { core::ptr::write_volatile(syst_cvr, 0) };
        unsafe { core::ptr::write_volatile(syst_csr, (1<<2) | (1<<1) | 1) };
    }

    pub unsafe fn init_tasks() {
        let (p0, p1, p2);

        unsafe {
            p0 = build_initial_psp(&mut STACKS[0].0, (task0_entry as usize) as u32);
            p1 = build_initial_psp(&mut STACKS[1].0, (task1_entry as usize) as u32);
            p2 = build_initial_psp(&mut STACKS[2].0, (task2_entry as usize) as u32);
            TCBS[0].sp = p0; TCBS[1].sp = p1; TCBS[2].sp = p2; CURR = 0;
        }
    }

    pub fn start() -> ! {
        unsafe {
            core::ptr::write_volatile(ICSR, 1 << 28);
        }
        loop { cortex_m::asm::wfi(); }
    }

    global_asm!(
        r#"
        .global PendSV
        .type   PendSV, %function
    PendSV:
        mrs     r0, psp
        stmdb   r0!, {{r4-r11}}
        bl      {switch}
        ldmia   r0!, {{r4-r11}}
        msr     psp, r0
        bx      lr
    "#

    , switch = sym crate::sched::pend_sv_switch_rust
    );

    pub extern "C" fn pend_sv_switch_rust(old_psp: u32) -> u32 {
        unsafe { TCBS[CURR].sp = old_psp; CURR = (CURR + 1) % N_TASKS; TCBS[CURR].sp }
    }

    #[exception]
    fn SysTick() { unsafe { core::ptr::write_volatile(ICSR, 1 << 28); } }
}

아 너무 어렵다.

0개의 댓글