source: rtems/cpukit/score/cpu/riscv/riscv-exception-handler.S @ e43994d

5
Last change on this file since e43994d was e43994d, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 27, 2018 at 8:05:50 AM

riscv: Optimize context switch and interrupts

Save/restore non-volatile registers in _CPU_Context_switch().

Save/restore volatile registers in _ISR_Handler().

Update #3433.

  • Property mode set to 100644
File size: 5.8 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup ScoreCPU
5 *
6 * @brief RISC-V exception support implementation.
7 */
8
9/*
10 * Copyright (c) 2018 embedded brains GmbH
11
12 * Copyright (c) 2015 University of York.
13 * Hesham Almatary <hesham@alumni.york.ac.uk>
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40
41#include <rtems/asm.h>
42#include <rtems/score/percpu.h>
43
44EXTERN(bsp_start_vector_table_begin)
45EXTERN(_Thread_Dispatch)
46PUBLIC(ISR_Handler)
47
48        .section        .text, "ax", @progbits
49        .align  2
50
51TYPE_FUNC(ISR_Handler)
52SYM(ISR_Handler):
53        addi    sp, sp, -CPU_INTERRUPT_FRAME_SIZE
54
55        /* Save */
56        SREG    a0, RISCV_INTERRUPT_FRAME_A0(sp)
57        SREG    a1, RISCV_INTERRUPT_FRAME_A1(sp)
58        SREG    a2, RISCV_INTERRUPT_FRAME_A2(sp)
59        SREG    s0, RISCV_INTERRUPT_FRAME_S0(sp)
60        csrr    a0, mcause
61        csrr    a1, mstatus
62        csrr    a2, mepc
63        GET_SELF_CPU_CONTROL    s0
64        SREG    s1, RISCV_INTERRUPT_FRAME_S1(sp)
65        SREG    ra, RISCV_INTERRUPT_FRAME_RA(sp)
66        SREG    a3, RISCV_INTERRUPT_FRAME_A3(sp)
67        SREG    a4, RISCV_INTERRUPT_FRAME_A4(sp)
68        SREG    a5, RISCV_INTERRUPT_FRAME_A5(sp)
69        SREG    a6, RISCV_INTERRUPT_FRAME_A6(sp)
70        SREG    a7, RISCV_INTERRUPT_FRAME_A7(sp)
71        SREG    t0, RISCV_INTERRUPT_FRAME_T0(sp)
72        SREG    t1, RISCV_INTERRUPT_FRAME_T1(sp)
73        SREG    t2, RISCV_INTERRUPT_FRAME_T2(sp)
74        SREG    t3, RISCV_INTERRUPT_FRAME_T3(sp)
75        SREG    t4, RISCV_INTERRUPT_FRAME_T4(sp)
76        SREG    t5, RISCV_INTERRUPT_FRAME_T5(sp)
77        SREG    t6, RISCV_INTERRUPT_FRAME_T6(sp)
78        SREG    a1, RISCV_INTERRUPT_FRAME_MSTATUS(sp)
79        SREG    a2, RISCV_INTERRUPT_FRAME_MEPC(sp)
80
81        /* FIXME Only handle interrupts for now (MSB = 1) */
82        andi    a0, a0, 0xf
83
84        /* Increment interrupt nest and thread dispatch disable level */
85        lw      t0, PER_CPU_ISR_NEST_LEVEL(s0)
86        lw      t1, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(s0)
87        addi    t2, t0, 1
88        addi    t1, t1, 1
89        sw      t2, PER_CPU_ISR_NEST_LEVEL(s0)
90        sw      t1, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(s0)
91
92        /* Keep sp (Exception frame address) in s1 */
93        mv      s1, sp
94
95        /* Call the exception handler from vector table */
96
97        /* First function arg for C handler is vector number,
98                * and the second is a pointer to exception frame.
99                * a0/mcause/vector number is already loaded above */
100        mv      a1, sp
101
102        /* calculate the offset */
103        la      t5, bsp_start_vector_table_begin
104#if     __riscv_xlen == 32
105        slli    t6, a0, 2
106#else   /* xlen = 64 */
107        slli    t6, a0, 3
108#endif
109        add     t5, t5, t6
110        LREG    t5, (t5)
111
112        /* Switch to interrupt stack if necessary */
113        bnez    t0, .Linterrupt_stack_switch_done
114        LREG    sp, PER_CPU_INTERRUPT_STACK_HIGH(s0)
115.Linterrupt_stack_switch_done:
116
117        jalr    t5
118
119        /* Load some per-CPU variables */
120        lw      t0, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(s0)
121        lbu     t1, PER_CPU_DISPATCH_NEEDED(s0)
122        lw      t2, PER_CPU_ISR_DISPATCH_DISABLE(s0)
123        lw      t3, PER_CPU_ISR_NEST_LEVEL(s0)
124
125        /* Restore stack pointer */
126        mv      sp, s1
127
128        /* Decrement levels and determine thread dispatch state */
129        xor     t1, t1, t0
130        addi    t0, t0, -1
131        or      t1, t1, t0
132        or      t1, t1, t2
133        addi    t3, t3, -1
134
135        /* Store thread dispatch disable and ISR nest levels */
136        sw      t0, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(s0)
137        sw      t3, PER_CPU_ISR_NEST_LEVEL(s0)
138
139        /*
140         * Check thread dispatch necessary, ISR dispatch disable and thread
141         * dispatch disable level.
142         */
143        bnez    t1, .Lthread_dispatch_done
144
145.Ldo_thread_dispatch:
146
147        /* Set ISR dispatch disable and thread dispatch disable level to one */
148        li      t0, 1
149        sw      t0, PER_CPU_ISR_DISPATCH_DISABLE(s0)
150        sw      t0, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(s0)
151
152        /* Call _Thread_Do_dispatch(), this function will enable interrupts */
153        mv      a0, s0
154        li      a1, RISCV_MSTATUS_MIE
155        call    _Thread_Do_dispatch
156
157        /* Disable interrupts */
158        csrrc   zero, mstatus, RISCV_MSTATUS_MIE
159
160#ifdef RTEMS_SMP
161        GET_SELF_CPU_CONTROL    s0
162#endif
163
164        /* Check if we have to do the thread dispatch again */
165        lbu     t0, PER_CPU_DISPATCH_NEEDED(s0)
166        bnez    t0, .Ldo_thread_dispatch
167
168        /* We are done with thread dispatching */
169        sw      zero, PER_CPU_ISR_DISPATCH_DISABLE(s0)
170
171.Lthread_dispatch_done:
172
173        /* Restore */
174        LREG    a0, RISCV_INTERRUPT_FRAME_MSTATUS(sp)
175        LREG    a1, RISCV_INTERRUPT_FRAME_MEPC(sp)
176        LREG    a2, RISCV_INTERRUPT_FRAME_A2(sp)
177        LREG    s0, RISCV_INTERRUPT_FRAME_S0(sp)
178        LREG    s1, RISCV_INTERRUPT_FRAME_S1(sp)
179        LREG    ra, RISCV_INTERRUPT_FRAME_RA(sp)
180        LREG    a3, RISCV_INTERRUPT_FRAME_A3(sp)
181        LREG    a4, RISCV_INTERRUPT_FRAME_A4(sp)
182        LREG    a5, RISCV_INTERRUPT_FRAME_A5(sp)
183        LREG    a6, RISCV_INTERRUPT_FRAME_A6(sp)
184        LREG    a7, RISCV_INTERRUPT_FRAME_A7(sp)
185        LREG    t0, RISCV_INTERRUPT_FRAME_T0(sp)
186        LREG    t1, RISCV_INTERRUPT_FRAME_T1(sp)
187        LREG    t2, RISCV_INTERRUPT_FRAME_T2(sp)
188        LREG    t3, RISCV_INTERRUPT_FRAME_T3(sp)
189        LREG    t4, RISCV_INTERRUPT_FRAME_T4(sp)
190        LREG    t5, RISCV_INTERRUPT_FRAME_T5(sp)
191        LREG    t6, RISCV_INTERRUPT_FRAME_T6(sp)
192        csrw    mstatus, a0
193        csrw    mepc, a1
194        LREG    a0, RISCV_INTERRUPT_FRAME_A0(sp)
195        LREG    a1, RISCV_INTERRUPT_FRAME_A1(sp)
196
197        addi    sp, sp, CPU_INTERRUPT_FRAME_SIZE
198
199        mret
Note: See TracBrowser for help on using the repository browser.