trap.c 5.4 KB
Newer Older
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2013-07-20     Bernard      first version
 */

#include <rtthread.h>
#include <rthw.h>
#include <board.h>

#include <armv8.h>
#include <interrupt.h>

#ifdef RT_USING_FINSH
extern long list_thread(void);
#endif

/**
 * this function will show registers of CPU
 *
 * @param regs the registers point
 */
void rt_hw_show_register(struct rt_hw_exp_stack *regs)
{
    rt_kprintf("Execption:\n");
    rt_kprintf("X00:0x%16.16p X01:0x%16.16p X02:0x%16.16p X03:0x%16.16p\n", (void *)regs->x0, (void *)regs->x1, (void *)regs->x2, (void *)regs->x3);
    rt_kprintf("X04:0x%16.16p X05:0x%16.16p X06:0x%16.16p X07:0x%16.16p\n", (void *)regs->x4, (void *)regs->x5, (void *)regs->x6, (void *)regs->x7);
    rt_kprintf("X08:0x%16.16p X09:0x%16.16p X10:0x%16.16p X11:0x%16.16p\n", (void *)regs->x8, (void *)regs->x9, (void *)regs->x10, (void *)regs->x11);
    rt_kprintf("X12:0x%16.16p X13:0x%16.16p X14:0x%16.16p X15:0x%16.16p\n", (void *)regs->x12, (void *)regs->x13, (void *)regs->x14, (void *)regs->x15);
    rt_kprintf("X16:0x%16.16p X17:0x%16.16p X18:0x%16.16p X19:0x%16.16p\n", (void *)regs->x16, (void *)regs->x17, (void *)regs->x18, (void *)regs->x19);
    rt_kprintf("X20:0x%16.16p X21:0x%16.16p X22:0x%16.16p X23:0x%16.16p\n", (void *)regs->x20, (void *)regs->x21, (void *)regs->x22, (void *)regs->x23);
    rt_kprintf("X24:0x%16.16p X25:0x%16.16p X26:0x%16.16p X27:0x%16.16p\n", (void *)regs->x24, (void *)regs->x25, (void *)regs->x26, (void *)regs->x27);
    rt_kprintf("X28:0x%16.16p X29:0x%16.16p X30:0x%16.16p\n", (void *)regs->x28, (void *)regs->x29, (void *)regs->x30);
    rt_kprintf("SPSR  :0x%16.16p\n", (void *)regs->spsr);
    rt_kprintf("EPC   :0x%16.16p\n", (void *)regs->pc);
}

/**
 * When comes across an instruction which it cannot handle,
 * it takes the undefined instruction trap.
 *
 * @param regs system registers
 *
 * @note never invoke this function in application
 */
void rt_hw_trap_error(struct rt_hw_exp_stack *regs)
{
    rt_kprintf("error exception:\n");
    rt_hw_show_register(regs);
#ifdef RT_USING_FINSH
    list_thread();
#endif
    rt_hw_cpu_shutdown();
}

void rt_hw_trap_irq(void)
{
#ifndef BSP_USING_GIC
    void *param;
    uint32_t irq;
    rt_isr_handler_t isr_func;
    extern struct rt_irq_desc isr_table[];
G
GuEe-GUI 已提交
67
    uint32_t value = IRQ_PEND_BASIC & 0x3ff;
68 69

#ifdef RT_USING_SMP
G
GuEe-GUI 已提交
70 71 72 73
    uint32_t cpu_id = rt_hw_cpu_id();
    uint32_t mailbox_data = IPI_MAILBOX_CLEAR(cpu_id);
#else
    uint32_t cpu_id = 0;
74 75
#endif
    uint32_t int_source = CORE_IRQSOURCE(cpu_id) & 0x3ff;
G
GuEe-GUI 已提交
76

77 78 79 80 81 82 83 84 85 86 87
    if (int_source & 0x02)
    {
        isr_func = isr_table[IRQ_ARM_TIMER].handler;
#ifdef RT_USING_INTERRUPT_INFO
        isr_table[IRQ_ARM_TIMER].counter++;
#endif
        if (isr_func)
        {
            param = isr_table[IRQ_ARM_TIMER].param;
            isr_func(IRQ_ARM_TIMER, param);
        }
G
GuEe-GUI 已提交
88
        return;
89
    }
G
GuEe-GUI 已提交
90 91 92 93 94 95 96 97 98 99 100 101

#ifdef RT_USING_SMP
    if (int_source & 0xf0)
    {
        /* it's a ipi interrupt */
        if (mailbox_data & 0x1)
        {
            /* clear mailbox */
            IPI_MAILBOX_CLEAR(cpu_id) = mailbox_data;
            isr_func = isr_table[IRQ_ARM_MAILBOX].handler;
#ifdef RT_USING_INTERRUPT_INFO
            isr_table[IRQ_ARM_MAILBOX].counter++;
102
#endif
G
GuEe-GUI 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115
            if (isr_func)
            {
                param = isr_table[IRQ_ARM_MAILBOX].param;
                isr_func(IRQ_ARM_MAILBOX, param);
            }
        }
        else
        {
            CORE_MAILBOX3_CLEAR(cpu_id) = mailbox_data;
        }
        return;
    }
#endif /* RT_USING_SMP */
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150

    /* local interrupt*/
    if (value)
    {
        if (value & (1 << 8))
        {
            value = IRQ_PEND1;
            irq = __rt_ffs(value) - 1;
        }
        else if (value & (1 << 9))
        {
            value = IRQ_PEND2;
            irq = __rt_ffs(value) + 31;
        }
        else
        {
            value &= 0x0f;
            irq = __rt_ffs(value) + 63;
        }

        /* get interrupt service routine */
        isr_func = isr_table[irq].handler;
#ifdef RT_USING_INTERRUPT_INFO
        isr_table[irq].counter++;
#endif
        if (isr_func)
        {
            /* Interrupt for myself. */
            param = isr_table[irq].param;
            /* turn to interrupt service routine */
            isr_func(irq, param);
        }
    }
#else
    void *param;
151
    int ir, ir_self;
152 153 154 155 156 157 158 159 160 161 162
    rt_isr_handler_t isr_func;
    extern struct rt_irq_desc isr_table[];

    ir = rt_hw_interrupt_get_irq();

    if (ir == 1023)
    {
        /* Spurious interrupt */
        return;
    }

163 164 165
    /* bit 10~12 is cpuid, bit 0~9 is interrupt id */
    ir_self = ir & 0x3ffUL;

166
    /* get interrupt service routine */
167
    isr_func = isr_table[ir_self].handler;
168
#ifdef RT_USING_INTERRUPT_INFO
169
    isr_table[ir_self].counter++;
170 171 172 173
#endif
    if (isr_func)
    {
        /* Interrupt for myself. */
174
        param = isr_table[ir_self].param;
175
        /* turn to interrupt service routine */
176
        isr_func(ir_self, param);
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
    }

    /* end of interrupt */
    rt_hw_interrupt_ack(ir);
#endif
}

void rt_hw_trap_fiq(void)
{
    void *param;
    int ir;
    rt_isr_handler_t isr_func;
    extern struct rt_irq_desc isr_table[];

    ir = rt_hw_interrupt_get_irq();

    /* get interrupt service routine */
    isr_func = isr_table[ir].handler;
    param = isr_table[ir].param;

    /* turn to interrupt service routine */
    isr_func(ir, param);

    /* end of interrupt */
    rt_hw_interrupt_ack(ir);
}