littlekernel / lk

LK embedded kernel
MIT License
3.11k stars 613 forks source link

Porting RISC-V processor with CLIC interrupt system #279

Closed fanghuaqi closed 3 years ago

fanghuaqi commented 3 years ago

Hi there, I am working on porting RISC-V processor with clic interrupt system, not the clint + plic version.

For clic spec, please check https://github.com/riscv/riscv-fast-interrupt/blob/master/clic.adoc

I tried to use a lowest priority interrupt(Machine software interrupt) to do context switch, but I found that if I trigger this interrupt in task context, it will not be handled due to interrupt is disabled globally, but if I enable irq, the kernel will work incorrectly, could you give me some hints on it?

You can find my porting code in https://github.com/nuclei-community/lk/tree/dev_nuclei/arch/riscv

Thanks Huaqi

fanghuaqi commented 3 years ago

Hi there, I updated the code with more details, in the portable code of arch_context_switch function, I use software interrupt function to trigger thread switch, in interrupt context switch it is ok, since the interrupt will be reenabled, but if I do it in task switch, the interrupt is disabled before arch_context_switch, so I just use spin_unlock to remove lock and use arch_enable_ints to re-enable interrupt? Is it ok?

void arch_context_switch(thread_t *oldthread, thread_t *newthread) {
    DEBUG_ASSERT(arch_ints_disabled());
    if (oldthread->stack_size > 0) {
        if (newthread->stack_size == 0) { // switch back to idle task, manually create a stack for it
            newthread->stack = initial_stack;
            newthread->stack_size = sizeof(initial_stack);
            newthread->entry= idle_thread_routine;
            arch_thread_initialize(newthread);
        }

        rt_interrupt_from_thread = &(oldthread->arch.cs_frame);
        rt_interrupt_to_thread = &(newthread->arch.cs_frame);
        riscv_trigger_preempt(); // trigger a software interrupt to do task context switch
        if (rt_thread_switch_interrupt_flag == 0) { // task switch in task context
            spin_unlock(&thread_lock); // remove lock, otherwise the thread might spin in lock 
            arch_enable_ints();   // enable interrupt for software interrupt come
        }
    } else { // First task started, switch from idle
        arch_context_start((unsigned long)&(newthread->arch.cs_frame));
        // never return
    }
}

Or is there any porting requirements for this arch_context_switch function?

Thanks Huaqi

fanghuaqi commented 3 years ago

Fixed in latest commit https://github.com/nuclei-community/lk/tree/dev_nuclei/arch/riscv

fanghuaqi commented 3 years ago

See PR #281