398 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			398 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * Copyright (c) 2006-2021, RT-Thread Development Team | ||
|  |  * | ||
|  |  * SPDX-License-Identifier: Apache-2.0 | ||
|  |  * | ||
|  |  * Change Logs: | ||
|  |  * Date           Author       Notes | ||
|  |  * 2018/10/01     Bernard      The first version | ||
|  |  * 2018/12/27     Jesven       Change irq enable/disable to cpu0 | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <rthw.h>
 | ||
|  | 
 | ||
|  | #include "tick.h"
 | ||
|  | 
 | ||
|  | #include <plic.h>
 | ||
|  | #include <clint.h>
 | ||
|  | #include <interrupt.h>
 | ||
|  | 
 | ||
|  | #define CPU_NUM         2
 | ||
|  | #define MAX_HANDLERS    IRQN_MAX
 | ||
|  | 
 | ||
|  | static struct rt_irq_desc irq_desc[MAX_HANDLERS]; | ||
|  | 
 | ||
|  | static rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param) | ||
|  | { | ||
|  |     rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector); | ||
|  |     return RT_NULL; | ||
|  | } | ||
|  | 
 | ||
|  | int rt_hw_clint_ipi_enable(void) | ||
|  | { | ||
|  |     /* Set the Machine-Software bit in MIE */ | ||
|  |     set_csr(mie, MIP_MSIP); | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | int rt_hw_clint_ipi_disable(void) | ||
|  | { | ||
|  |     /* Clear the Machine-Software bit in MIE */ | ||
|  |     clear_csr(mie, MIP_MSIP); | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | int rt_hw_plic_irq_enable(plic_irq_t irq_number) | ||
|  | { | ||
|  |     unsigned long core_id = 0; | ||
|  | 
 | ||
|  |     /* Check parameters */ | ||
|  |     if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) | ||
|  |         return -1; | ||
|  |     /* Get current enable bit array by IRQ number */ | ||
|  |     uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32]; | ||
|  |     /* Set enable bit in enable bit array */ | ||
|  |     current |= (uint32_t)1 << (irq_number % 32); | ||
|  |     /* Write back the enable bit array */ | ||
|  |     plic->target_enables.target[core_id].enable[irq_number / 32] = current; | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | int rt_hw_plic_irq_disable(plic_irq_t irq_number) | ||
|  | { | ||
|  |     unsigned long core_id = 0; | ||
|  | 
 | ||
|  |     /* Check parameters */ | ||
|  |     if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number) | ||
|  |         return -1; | ||
|  |     /* Get current enable bit array by IRQ number */ | ||
|  |     uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32]; | ||
|  |     /* Clear enable bit in enable bit array */ | ||
|  |     current &= ~((uint32_t)1 << (irq_number % 32)); | ||
|  |     /* Write back the enable bit array */ | ||
|  |     plic->target_enables.target[core_id].enable[irq_number / 32] = current; | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * This function will initialize hardware interrupt | ||
|  |  */ | ||
|  | void rt_hw_interrupt_init(void) | ||
|  | { | ||
|  |     int idx; | ||
|  |     int cpuid; | ||
|  | 
 | ||
|  |     cpuid = current_coreid(); | ||
|  | 
 | ||
|  |     /* Disable all interrupts for the current core. */ | ||
|  |     for (idx = 0; idx < ((PLIC_NUM_SOURCES + 32u) / 32u); idx ++) | ||
|  |         plic->target_enables.target[cpuid].enable[idx] = 0; | ||
|  | 
 | ||
|  |     /* Set priorities to zero. */ | ||
|  |     for (idx = 0; idx < PLIC_NUM_SOURCES; idx++) | ||
|  |         plic->source_priorities.priority[idx] = 0; | ||
|  | 
 | ||
|  |     /* Set the threshold to zero. */ | ||
|  |     plic->targets.target[cpuid].priority_threshold = 0; | ||
|  | 
 | ||
|  |     /* init exceptions table */ | ||
|  |     for (idx = 0; idx < MAX_HANDLERS; idx++) | ||
|  |     { | ||
|  |         rt_hw_interrupt_mask(idx); | ||
|  |         irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle; | ||
|  |         irq_desc[idx].param = RT_NULL; | ||
|  | #ifdef RT_USING_INTERRUPT_INFO
 | ||
|  |         rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default"); | ||
|  |         irq_desc[idx].counter = 0; | ||
|  | #endif
 | ||
|  |     } | ||
|  | 
 | ||
|  |     /* Enable machine external interrupts. */ | ||
|  |     set_csr(mie, MIP_MEIP); | ||
|  | } | ||
|  | 
 | ||
|  | void rt_hw_scondary_interrupt_init(void) | ||
|  | { | ||
|  |     int idx; | ||
|  |     int cpuid; | ||
|  | 
 | ||
|  |     cpuid = current_coreid(); | ||
|  | 
 | ||
|  |     /* Disable all interrupts for the current core. */ | ||
|  |     for (idx = 0; idx < ((PLIC_NUM_SOURCES + 32u) / 32u); idx ++) | ||
|  |         plic->target_enables.target[cpuid].enable[idx] = 0; | ||
|  | 
 | ||
|  |     /* Set the threshold to zero. */ | ||
|  |     plic->targets.target[cpuid].priority_threshold = 0; | ||
|  | 
 | ||
|  |     /* Enable machine external interrupts. */ | ||
|  |     set_csr(mie, MIP_MEIP); | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * This function will mask a interrupt. | ||
|  |  * @param vector the interrupt number | ||
|  |  */ | ||
|  | void rt_hw_interrupt_mask(int vector) | ||
|  | { | ||
|  |     rt_hw_plic_irq_disable(vector); | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * This function will un-mask a interrupt. | ||
|  |  * @param vector the interrupt number | ||
|  |  */ | ||
|  | void rt_hw_interrupt_umask(int vector) | ||
|  | { | ||
|  |     plic_set_priority(vector, 1); | ||
|  |     rt_hw_plic_irq_enable(vector); | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * This function will install a interrupt service routine to a interrupt. | ||
|  |  * @param vector the interrupt number | ||
|  |  * @param new_handler the interrupt service routine to be installed | ||
|  |  * @param old_handler the old interrupt service routine | ||
|  |  */ | ||
|  | rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, | ||
|  |         void *param, const char *name) | ||
|  | { | ||
|  |     rt_isr_handler_t old_handler = RT_NULL; | ||
|  | 
 | ||
|  |     if(vector < MAX_HANDLERS) | ||
|  |     { | ||
|  |         old_handler = irq_desc[vector].handler; | ||
|  |         if (handler != RT_NULL) | ||
|  |         { | ||
|  |             irq_desc[vector].handler = (rt_isr_handler_t)handler; | ||
|  |             irq_desc[vector].param = param; | ||
|  | #ifdef RT_USING_INTERRUPT_INFO
 | ||
|  |             rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name); | ||
|  |             irq_desc[vector].counter = 0; | ||
|  | #endif
 | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return old_handler; | ||
|  | } | ||
|  | 
 | ||
|  | RT_WEAK | ||
|  | void plic_irq_handle(plic_irq_t irq) | ||
|  | { | ||
|  |     rt_kprintf("UN-handled interrupt %d occurred!!!\n", irq); | ||
|  |     return ; | ||
|  | } | ||
|  | 
 | ||
|  | uintptr_t handle_irq_m_ext(uintptr_t cause, uintptr_t epc) | ||
|  | { | ||
|  |     /*
 | ||
|  |      * After the highest-priority pending interrupt is claimed by a target | ||
|  |      * and the corresponding IP bit is cleared, other lower-priority | ||
|  |      * pending interrupts might then become visible to the target, and so | ||
|  |      * the PLIC EIP bit might not be cleared after a claim. The interrupt | ||
|  |      * handler can check the local meip/heip/seip/ueip bits before exiting | ||
|  |      * the handler, to allow more efficient service of other interrupts | ||
|  |      * without first restoring the interrupted context and taking another | ||
|  |      * interrupt trap. | ||
|  |      */ | ||
|  |     if (read_csr(mip) & MIP_MEIP) | ||
|  |     { | ||
|  |         /* Get current core id */ | ||
|  |         uint64_t core_id = current_coreid(); | ||
|  |         /* Get primitive interrupt enable flag */ | ||
|  |         uint64_t ie_flag = read_csr(mie); | ||
|  |         /* Get current IRQ num */ | ||
|  |         uint32_t int_num = plic->targets.target[core_id].claim_complete; | ||
|  |         /* Get primitive IRQ threshold */ | ||
|  |         uint32_t int_threshold = plic->targets.target[core_id].priority_threshold; | ||
|  |         /* Set new IRQ threshold = current IRQ threshold */ | ||
|  |         plic->targets.target[core_id].priority_threshold = plic->source_priorities.priority[int_num]; | ||
|  | 
 | ||
|  |         /* Disable software interrupt and timer interrupt */ | ||
|  |         clear_csr(mie, MIP_MTIP | MIP_MSIP); | ||
|  | 
 | ||
|  |         if (irq_desc[int_num].handler == (rt_isr_handler_t)rt_hw_interrupt_handle) | ||
|  |         { | ||
|  |             /* default handler, route to kendryte bsp plic driver */ | ||
|  |             plic_irq_handle(int_num); | ||
|  |         } | ||
|  |         else if (irq_desc[int_num].handler) | ||
|  |         { | ||
|  |             irq_desc[int_num].handler(int_num, irq_desc[int_num].param); | ||
|  |         } | ||
|  | 
 | ||
|  |         /* Perform IRQ complete */ | ||
|  |         plic->targets.target[core_id].claim_complete = int_num; | ||
|  |         /* Set MPIE and MPP flag used to MRET instructions restore MIE flag */ | ||
|  |         set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP); | ||
|  |         /* Restore primitive interrupt enable flag */ | ||
|  |         write_csr(mie, ie_flag); | ||
|  |         /* Restore primitive IRQ threshold */ | ||
|  |         plic->targets.target[core_id].priority_threshold = int_threshold; | ||
|  |     } | ||
|  | 
 | ||
|  |     return epc; | ||
|  | } | ||
|  | struct exception_stack_frame | ||
|  | { | ||
|  |     uint64_t x1; | ||
|  |     uint64_t x2; | ||
|  |     uint64_t x3; | ||
|  |     uint64_t x4; | ||
|  |     uint64_t x5; | ||
|  |     uint64_t x6; | ||
|  |     uint64_t x7; | ||
|  |     uint64_t x8; | ||
|  |     uint64_t x9; | ||
|  |     uint64_t x10; | ||
|  |     uint64_t x11; | ||
|  |     uint64_t x12; | ||
|  |     uint64_t x13; | ||
|  |     uint64_t x14; | ||
|  |     uint64_t x15; | ||
|  |     uint64_t x16; | ||
|  |     uint64_t x17; | ||
|  |     uint64_t x18; | ||
|  |     uint64_t x19; | ||
|  |     uint64_t x20; | ||
|  |     uint64_t x21; | ||
|  |     uint64_t x22; | ||
|  |     uint64_t x23; | ||
|  |     uint64_t x24; | ||
|  |     uint64_t x25; | ||
|  |     uint64_t x26; | ||
|  |     uint64_t x27; | ||
|  |     uint64_t x28; | ||
|  |     uint64_t x29; | ||
|  |     uint64_t x30; | ||
|  |     uint64_t x31; | ||
|  | }; | ||
|  | 
 | ||
|  | void print_stack_frame(uintptr_t * sp) | ||
|  | { | ||
|  |     struct exception_stack_frame * esf = (struct exception_stack_frame *)(sp+1); | ||
|  | 
 | ||
|  |     rt_kprintf("\n=================================================================\n"); | ||
|  |     rt_kprintf("x1 (ra   : Return address                ) ==> 0x%08x%08x\n", esf->x1 >> 32  , esf->x1 & UINT32_MAX); | ||
|  |     rt_kprintf("x2 (sp   : Stack pointer                 ) ==> 0x%08x%08x\n", esf->x2 >> 32  , esf->x2 & UINT32_MAX); | ||
|  |     rt_kprintf("x3 (gp   : Global pointer                ) ==> 0x%08x%08x\n", esf->x3 >> 32  , esf->x3 & UINT32_MAX); | ||
|  |     rt_kprintf("x4 (tp   : Thread pointer                ) ==> 0x%08x%08x\n", esf->x4 >> 32  , esf->x4 & UINT32_MAX); | ||
|  |     rt_kprintf("x5 (t0   : Temporary                     ) ==> 0x%08x%08x\n", esf->x5 >> 32  , esf->x5 & UINT32_MAX); | ||
|  |     rt_kprintf("x6 (t1   : Temporary                     ) ==> 0x%08x%08x\n", esf->x6 >> 32  , esf->x6 & UINT32_MAX); | ||
|  |     rt_kprintf("x7 (t2   : Temporary                     ) ==> 0x%08x%08x\n", esf->x7 >> 32  , esf->x7 & UINT32_MAX); | ||
|  |     rt_kprintf("x8 (s0/fp: Save register,frame pointer   ) ==> 0x%08x%08x\n", esf->x8 >> 32  , esf->x8 & UINT32_MAX); | ||
|  |     rt_kprintf("x9 (s1   : Save register                 ) ==> 0x%08x%08x\n", esf->x9 >> 32  , esf->x9 & UINT32_MAX); | ||
|  |     rt_kprintf("x10(a0   : Function argument,return value) ==> 0x%08x%08x\n", esf->x10 >> 32 , esf->x10 & UINT32_MAX); | ||
|  |     rt_kprintf("x11(a1   : Function argument,return value) ==> 0x%08x%08x\n", esf->x11 >> 32 , esf->x11 & UINT32_MAX); | ||
|  |     rt_kprintf("x12(a2   : Function argument             ) ==> 0x%08x%08x\n", esf->x12 >> 32 , esf->x12 & UINT32_MAX); | ||
|  |     rt_kprintf("x13(a3   : Function argument             ) ==> 0x%08x%08x\n", esf->x13 >> 32 , esf->x13 & UINT32_MAX); | ||
|  |     rt_kprintf("x14(a4   : Function argument             ) ==> 0x%08x%08x\n", esf->x14 >> 32 , esf->x14 & UINT32_MAX); | ||
|  |     rt_kprintf("x15(a5   : Function argument             ) ==> 0x%08x%08x\n", esf->x15 >> 32 , esf->x15 & UINT32_MAX); | ||
|  |     rt_kprintf("x16(a6   : Function argument             ) ==> 0x%08x%08x\n", esf->x16 >> 32 , esf->x16 & UINT32_MAX); | ||
|  |     rt_kprintf("x17(a7   : Function argument             ) ==> 0x%08x%08x\n", esf->x17 >> 32 , esf->x17 & UINT32_MAX); | ||
|  |     rt_kprintf("x18(s2   : Save register                 ) ==> 0x%08x%08x\n", esf->x18 >> 32 , esf->x18 & UINT32_MAX); | ||
|  |     rt_kprintf("x19(s3   : Save register                 ) ==> 0x%08x%08x\n", esf->x19 >> 32 , esf->x19 & UINT32_MAX); | ||
|  |     rt_kprintf("x20(s4   : Save register                 ) ==> 0x%08x%08x\n", esf->x20 >> 32 , esf->x20 & UINT32_MAX); | ||
|  |     rt_kprintf("x21(s5   : Save register                 ) ==> 0x%08x%08x\n", esf->x21 >> 32 , esf->x21 & UINT32_MAX); | ||
|  |     rt_kprintf("x22(s6   : Save register                 ) ==> 0x%08x%08x\n", esf->x22 >> 32 , esf->x22 & UINT32_MAX); | ||
|  |     rt_kprintf("x23(s7   : Save register                 ) ==> 0x%08x%08x\n", esf->x23 >> 32 , esf->x23 & UINT32_MAX); | ||
|  |     rt_kprintf("x24(s8   : Save register                 ) ==> 0x%08x%08x\n", esf->x24 >> 32 , esf->x24 & UINT32_MAX); | ||
|  |     rt_kprintf("x25(s9   : Save register                 ) ==> 0x%08x%08x\n", esf->x25 >> 32 , esf->x25 & UINT32_MAX); | ||
|  |     rt_kprintf("x26(s10  : Save register                 ) ==> 0x%08x%08x\n", esf->x26 >> 32 , esf->x26 & UINT32_MAX); | ||
|  |     rt_kprintf("x27(s11  : Save register                 ) ==> 0x%08x%08x\n", esf->x27 >> 32 , esf->x27 & UINT32_MAX); | ||
|  |     rt_kprintf("x28(t3   : Temporary                     ) ==> 0x%08x%08x\n", esf->x28 >> 32 , esf->x28 & UINT32_MAX); | ||
|  |     rt_kprintf("x29(t4   : Temporary                     ) ==> 0x%08x%08x\n", esf->x29 >> 32 , esf->x29 & UINT32_MAX); | ||
|  |     rt_kprintf("x30(t5   : Temporary                     ) ==> 0x%08x%08x\n", esf->x30 >> 32 , esf->x30 & UINT32_MAX); | ||
|  |     rt_kprintf("x31(t6   : Temporary                     ) ==> 0x%08x%08x\n", esf->x31 >> 32 , esf->x31 & UINT32_MAX); | ||
|  |     rt_kprintf("=================================================================\n"); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc, uintptr_t * sp) | ||
|  | { | ||
|  |     int cause = mcause & CAUSE_MACHINE_IRQ_REASON_MASK; | ||
|  | 
 | ||
|  |     if (mcause & (1UL << 63)) | ||
|  |     { | ||
|  |         switch (cause) | ||
|  |         { | ||
|  |             case IRQ_M_SOFT: | ||
|  |                 { | ||
|  |                     uint64_t core_id = current_coreid(); | ||
|  | 
 | ||
|  |                     clint_ipi_clear(core_id); | ||
|  |                     rt_schedule(); | ||
|  |                 } | ||
|  |                 break; | ||
|  |             case IRQ_M_EXT: | ||
|  |                 handle_irq_m_ext(mcause, epc); | ||
|  |                 break; | ||
|  |             case IRQ_M_TIMER: | ||
|  |                 tick_isr(); | ||
|  |                 break; | ||
|  |         } | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         rt_thread_t tid; | ||
|  |         extern long list_thread(); | ||
|  | 
 | ||
|  |         rt_hw_interrupt_disable(); | ||
|  | 
 | ||
|  |         tid = rt_thread_self(); | ||
|  |         rt_kprintf("\nException:\n"); | ||
|  |         switch (cause) | ||
|  |         { | ||
|  |             case CAUSE_MISALIGNED_FETCH: | ||
|  |                 rt_kprintf("Instruction address misaligned"); | ||
|  |                 break; | ||
|  |             case CAUSE_FAULT_FETCH: | ||
|  |                 rt_kprintf("Instruction access fault"); | ||
|  |                 break; | ||
|  |             case CAUSE_ILLEGAL_INSTRUCTION: | ||
|  |                 rt_kprintf("Illegal instruction"); | ||
|  |                 break; | ||
|  |             case CAUSE_BREAKPOINT: | ||
|  |                 rt_kprintf("Breakpoint"); | ||
|  |                 break; | ||
|  |             case CAUSE_MISALIGNED_LOAD: | ||
|  |                 rt_kprintf("Load address misaligned"); | ||
|  |                 break; | ||
|  |             case CAUSE_FAULT_LOAD: | ||
|  |                 rt_kprintf("Load access fault"); | ||
|  |                 break; | ||
|  |             case CAUSE_MISALIGNED_STORE: | ||
|  |                 rt_kprintf("Store address misaligned"); | ||
|  |                 break; | ||
|  |             case CAUSE_FAULT_STORE: | ||
|  |                 rt_kprintf("Store access fault"); | ||
|  |                 break; | ||
|  |             case CAUSE_USER_ECALL: | ||
|  |                 rt_kprintf("Environment call from U-mode"); | ||
|  |                 break; | ||
|  |             case CAUSE_SUPERVISOR_ECALL: | ||
|  |                 rt_kprintf("Environment call from S-mode"); | ||
|  |                 break; | ||
|  |             case CAUSE_HYPERVISOR_ECALL: | ||
|  |                 rt_kprintf("Environment call from H-mode"); | ||
|  |                 break; | ||
|  |             case CAUSE_MACHINE_ECALL: | ||
|  |                 rt_kprintf("Environment call from M-mode"); | ||
|  |                 break; | ||
|  |             default: | ||
|  |                 rt_kprintf("Uknown exception : %08lX", cause); | ||
|  |                 break; | ||
|  |         } | ||
|  |         rt_kprintf("\n"); | ||
|  |         print_stack_frame(sp); | ||
|  |         rt_kprintf("exception pc => 0x%08x\n", epc); | ||
|  |         rt_kprintf("current thread: %.*s\n", RT_NAME_MAX, tid->name); | ||
|  | #ifdef RT_USING_FINSH
 | ||
|  |         list_thread(); | ||
|  | #endif
 | ||
|  |         while(1); | ||
|  |     } | ||
|  | 
 | ||
|  |     return epc; | ||
|  | } |