2015-04-10 16:44:37 -07:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014 Wind River Systems, Inc.
|
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2015-04-10 16:44:37 -07:00
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2015-04-10 16:44:37 -07:00
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
2015-04-10 16:44:37 -07:00
|
|
|
*/
|
|
|
|
|
2015-12-04 10:09:39 -05:00
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* @brief Fault handlers for ARCv2
|
|
|
|
*
|
2015-04-10 16:44:37 -07:00
|
|
|
* Fault handlers for ARCv2 processors.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define _ASMLANGUAGE
|
|
|
|
|
|
|
|
#include <toolchain.h>
|
|
|
|
#include <sections.h>
|
2015-05-28 10:56:47 -07:00
|
|
|
#include <arch/cpu.h>
|
2015-04-10 16:44:37 -07:00
|
|
|
#include "swap_macros.h"
|
|
|
|
|
|
|
|
GTEXT(_Fault)
|
|
|
|
|
|
|
|
GTEXT(__reset)
|
|
|
|
GTEXT(__memory_error)
|
|
|
|
GTEXT(__instruction_error)
|
|
|
|
GTEXT(__ev_machine_check)
|
|
|
|
GTEXT(__ev_tlb_miss_i)
|
|
|
|
GTEXT(__ev_tlb_miss_d)
|
|
|
|
GTEXT(__ev_prot_v)
|
|
|
|
GTEXT(__ev_privilege_v)
|
|
|
|
GTEXT(__ev_swi)
|
|
|
|
GTEXT(__ev_trap)
|
|
|
|
GTEXT(__ev_extension)
|
|
|
|
GTEXT(__ev_div_zero)
|
|
|
|
GTEXT(__ev_dc_error)
|
|
|
|
GTEXT(__ev_maligned)
|
|
|
|
GDATA(_firq_stack)
|
|
|
|
|
|
|
|
SECTION_VAR(BSS, saved_stack_pointer)
|
|
|
|
.word 0
|
|
|
|
|
arc: trap handler, used by irq_offload, now handles thread switch
It was found that the test latency_measure, when compiled
for microkernel, would fail on the ARC. This because the
trap handler, used by irq_offload, wasn't supporting thread switching.
This submission adds the code to do that, and the code size is
bigger only when CONFIG_MICROKERNEL is defined.
To keep code a bit smaller, there is a trick exploited here where
the AE bit is cleared in the STATUS32 register and in AUX_IRQ_ACT,
bit 1 is set, to make it appear as if the machine has interrupted
at priority 1 level. It then can jump into some common interrupt
exit code for regular interrupts and perform an RTIE instruction
to switch into the new thread.
test/latency_measure/microkernel now passes.
Change-Id: I1872a80bb09a259814540567f51721203201679a
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-26 10:39:20 -07:00
|
|
|
#if CONFIG_NUM_IRQ_PRIO_LEVELS == 1
|
|
|
|
#error "NUM_IRQ_PRIO_LEVELS==1 is not supported."
|
|
|
|
/* The code below sets bit 1 in AUX_IRQ_ACT and thus requires
|
|
|
|
* priority 0 and 1 at a minimum. Supporting only 1 priority
|
|
|
|
* requires a change to this file but also changes to make
|
|
|
|
* FIRQ optional.
|
|
|
|
*/
|
|
|
|
#endif
|
|
|
|
|
2015-04-10 16:44:37 -07:00
|
|
|
/*
|
2015-07-01 17:51:40 -04:00
|
|
|
* @brief Fault handler installed in the fault and reserved vectors
|
2015-04-10 16:44:37 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__memory_error)
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__instruction_error)
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_machine_check)
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_tlb_miss_i)
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_tlb_miss_d)
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_prot_v)
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_privilege_v)
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_swi)
|
2015-11-17 14:08:45 -08:00
|
|
|
#ifndef CONFIG_IRQ_OFFLOAD
|
2015-04-10 16:44:37 -07:00
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap)
|
2015-11-17 14:08:45 -08:00
|
|
|
#endif
|
2015-04-10 16:44:37 -07:00
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_extension)
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_div_zero)
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_dc_error)
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_maligned)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Before invoking exception handler, the kernel switches to an exception
|
|
|
|
* stack, which is really the FIRQ stack, to save the faulting thread's
|
|
|
|
* registers. It can use the FIRQ stack because it knows it is unused
|
|
|
|
* since it is save to assume that if an exception has happened in FIRQ
|
|
|
|
* handler, the problem is fatal and all the kernel can do is just print
|
|
|
|
* a diagnostic message and halt.
|
|
|
|
*/
|
|
|
|
|
arc: trap handler, used by irq_offload, now handles thread switch
It was found that the test latency_measure, when compiled
for microkernel, would fail on the ARC. This because the
trap handler, used by irq_offload, wasn't supporting thread switching.
This submission adds the code to do that, and the code size is
bigger only when CONFIG_MICROKERNEL is defined.
To keep code a bit smaller, there is a trick exploited here where
the AE bit is cleared in the STATUS32 register and in AUX_IRQ_ACT,
bit 1 is set, to make it appear as if the machine has interrupted
at priority 1 level. It then can jump into some common interrupt
exit code for regular interrupts and perform an RTIE instruction
to switch into the new thread.
test/latency_measure/microkernel now passes.
Change-Id: I1872a80bb09a259814540567f51721203201679a
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-26 10:39:20 -07:00
|
|
|
#ifdef CONFIG_ARC_STACK_CHECKING
|
|
|
|
push_s r2
|
|
|
|
/* disable stack checking */
|
|
|
|
lr r2, [_ARC_V2_STATUS32]
|
|
|
|
bclr r2, r2, _ARC_V2_STATUS32_SC_BIT
|
|
|
|
kflag r2
|
|
|
|
pop_s r2
|
|
|
|
#endif
|
|
|
|
|
2015-04-10 16:44:37 -07:00
|
|
|
st sp, [saved_stack_pointer]
|
|
|
|
mov_s sp, _firq_stack
|
|
|
|
add sp, sp, CONFIG_FIRQ_STACK_SIZE
|
|
|
|
|
|
|
|
/* save caller saved registers */
|
|
|
|
_create_irq_stack_frame
|
|
|
|
|
arc: trap handler, used by irq_offload, now handles thread switch
It was found that the test latency_measure, when compiled
for microkernel, would fail on the ARC. This because the
trap handler, used by irq_offload, wasn't supporting thread switching.
This submission adds the code to do that, and the code size is
bigger only when CONFIG_MICROKERNEL is defined.
To keep code a bit smaller, there is a trick exploited here where
the AE bit is cleared in the STATUS32 register and in AUX_IRQ_ACT,
bit 1 is set, to make it appear as if the machine has interrupted
at priority 1 level. It then can jump into some common interrupt
exit code for regular interrupts and perform an RTIE instruction
to switch into the new thread.
test/latency_measure/microkernel now passes.
Change-Id: I1872a80bb09a259814540567f51721203201679a
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-26 10:39:20 -07:00
|
|
|
lr r0,[_ARC_V2_ERSTATUS]
|
|
|
|
st_s r0, [sp, __tISF_status32_OFFSET]
|
|
|
|
lr r0,[_ARC_V2_ERET]
|
|
|
|
st_s r0, [sp, __tISF_pc_OFFSET] /* eret into pc */
|
|
|
|
|
2015-04-10 16:44:37 -07:00
|
|
|
jl _Fault
|
|
|
|
|
|
|
|
/* if _Fault returns, restore the registers */
|
|
|
|
_pop_irq_stack_frame
|
|
|
|
|
|
|
|
/* now restore the stack */
|
|
|
|
ld sp,[saved_stack_pointer]
|
|
|
|
rtie
|
2015-11-17 14:08:45 -08:00
|
|
|
|
|
|
|
#ifdef CONFIG_IRQ_OFFLOAD
|
|
|
|
GTEXT(_irq_do_offload);
|
|
|
|
|
|
|
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap)
|
|
|
|
/*
|
|
|
|
* Before invoking exception handler, the kernel switches to an exception
|
|
|
|
* stack, which is really the FIRQ stack, to save the faulting thread's
|
|
|
|
* registers. It can use the FIRQ stack because it knows it is unused
|
2016-05-15 10:54:35 -07:00
|
|
|
* since it is safe to assume that if an exception has happened in FIRQ
|
2015-11-17 14:08:45 -08:00
|
|
|
* handler, the problem is fatal and all the kernel can do is just print
|
|
|
|
* a diagnostic message and halt.
|
|
|
|
*/
|
|
|
|
|
arc: trap handler, used by irq_offload, now handles thread switch
It was found that the test latency_measure, when compiled
for microkernel, would fail on the ARC. This because the
trap handler, used by irq_offload, wasn't supporting thread switching.
This submission adds the code to do that, and the code size is
bigger only when CONFIG_MICROKERNEL is defined.
To keep code a bit smaller, there is a trick exploited here where
the AE bit is cleared in the STATUS32 register and in AUX_IRQ_ACT,
bit 1 is set, to make it appear as if the machine has interrupted
at priority 1 level. It then can jump into some common interrupt
exit code for regular interrupts and perform an RTIE instruction
to switch into the new thread.
test/latency_measure/microkernel now passes.
Change-Id: I1872a80bb09a259814540567f51721203201679a
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-26 10:39:20 -07:00
|
|
|
#ifdef CONFIG_ARC_STACK_CHECKING
|
|
|
|
push_s r2
|
|
|
|
/* disable stack checking */
|
|
|
|
lr r2, [_ARC_V2_STATUS32]
|
|
|
|
bclr r2, r2, _ARC_V2_STATUS32_SC_BIT
|
|
|
|
kflag r2
|
|
|
|
pop_s r2
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef CONFIG_MICROKERNEL
|
2015-11-17 14:08:45 -08:00
|
|
|
st sp, [saved_stack_pointer]
|
|
|
|
mov_s sp, _firq_stack
|
|
|
|
add sp, sp, CONFIG_FIRQ_STACK_SIZE
|
arc: trap handler, used by irq_offload, now handles thread switch
It was found that the test latency_measure, when compiled
for microkernel, would fail on the ARC. This because the
trap handler, used by irq_offload, wasn't supporting thread switching.
This submission adds the code to do that, and the code size is
bigger only when CONFIG_MICROKERNEL is defined.
To keep code a bit smaller, there is a trick exploited here where
the AE bit is cleared in the STATUS32 register and in AUX_IRQ_ACT,
bit 1 is set, to make it appear as if the machine has interrupted
at priority 1 level. It then can jump into some common interrupt
exit code for regular interrupts and perform an RTIE instruction
to switch into the new thread.
test/latency_measure/microkernel now passes.
Change-Id: I1872a80bb09a259814540567f51721203201679a
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-26 10:39:20 -07:00
|
|
|
#endif
|
2015-11-17 14:08:45 -08:00
|
|
|
|
|
|
|
/* save caller saved registers */
|
|
|
|
_create_irq_stack_frame
|
|
|
|
|
arc: trap handler, used by irq_offload, now handles thread switch
It was found that the test latency_measure, when compiled
for microkernel, would fail on the ARC. This because the
trap handler, used by irq_offload, wasn't supporting thread switching.
This submission adds the code to do that, and the code size is
bigger only when CONFIG_MICROKERNEL is defined.
To keep code a bit smaller, there is a trick exploited here where
the AE bit is cleared in the STATUS32 register and in AUX_IRQ_ACT,
bit 1 is set, to make it appear as if the machine has interrupted
at priority 1 level. It then can jump into some common interrupt
exit code for regular interrupts and perform an RTIE instruction
to switch into the new thread.
test/latency_measure/microkernel now passes.
Change-Id: I1872a80bb09a259814540567f51721203201679a
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-26 10:39:20 -07:00
|
|
|
lr r0,[_ARC_V2_ERSTATUS]
|
|
|
|
st_s r0, [sp, __tISF_status32_OFFSET]
|
|
|
|
lr r0,[_ARC_V2_ERET]
|
|
|
|
st_s r0, [sp, __tISF_pc_OFFSET] /* eret into pc */
|
|
|
|
|
2015-11-17 14:08:45 -08:00
|
|
|
jl _irq_do_offload
|
|
|
|
|
arc: trap handler, used by irq_offload, now handles thread switch
It was found that the test latency_measure, when compiled
for microkernel, would fail on the ARC. This because the
trap handler, used by irq_offload, wasn't supporting thread switching.
This submission adds the code to do that, and the code size is
bigger only when CONFIG_MICROKERNEL is defined.
To keep code a bit smaller, there is a trick exploited here where
the AE bit is cleared in the STATUS32 register and in AUX_IRQ_ACT,
bit 1 is set, to make it appear as if the machine has interrupted
at priority 1 level. It then can jump into some common interrupt
exit code for regular interrupts and perform an RTIE instruction
to switch into the new thread.
test/latency_measure/microkernel now passes.
Change-Id: I1872a80bb09a259814540567f51721203201679a
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-26 10:39:20 -07:00
|
|
|
#ifdef CONFIG_MICROKERNEL
|
|
|
|
mov_s r1, _nanokernel
|
|
|
|
ld_s r2, [r1, __tNANO_current_OFFSET]
|
|
|
|
#if CONFIG_NUM_IRQ_PRIO_LEVELS > 1
|
|
|
|
/* check if we're a nested interrupt: if so, let the
|
|
|
|
* interrupted interrupt handle the reschedule
|
|
|
|
*/
|
|
|
|
lr r3, [_ARC_V2_AUX_IRQ_ACT]
|
|
|
|
/* the OS on ARCv2 always runs in kernel mode, so assume bit31 [U] in
|
|
|
|
* AUX_IRQ_ACT is always 0: if the contents of AUX_IRQ_ACT is 0, it
|
|
|
|
* means trap was taken from outside an interrupt handler.
|
|
|
|
* But if it was inside, let that handler do the swap.
|
|
|
|
*/
|
|
|
|
breq r3, 0, _trap_check_for_swap
|
|
|
|
_trap_return:
|
|
|
|
_pop_irq_stack_frame
|
|
|
|
rtie
|
|
|
|
#endif
|
|
|
|
|
|
|
|
.balign 4
|
|
|
|
_trap_check_for_swap:
|
|
|
|
ld_s r0, [r2, __tTCS_flags_OFFSET]
|
|
|
|
and.f r0, r0, PREEMPTIBLE
|
|
|
|
bnz _e_check_if_a_fiber_is_ready
|
|
|
|
b _trap_return
|
|
|
|
|
|
|
|
.balign 4
|
|
|
|
_e_check_if_a_fiber_is_ready:
|
|
|
|
ld_s r0, [r1, __tNANO_fiber_OFFSET] /* incoming fiber in r0 */
|
|
|
|
brne r0, 0, _trap_reschedule
|
|
|
|
b _trap_return
|
|
|
|
|
|
|
|
.balign 4
|
|
|
|
_trap_reschedule:
|
|
|
|
|
|
|
|
_save_callee_saved_regs
|
|
|
|
|
|
|
|
st _CAUSE_RIRQ, [r2, __tTCS_relinquish_cause_OFFSET]
|
|
|
|
/* note: Ok to use _CAUSE_RIRQ since everything is saved */
|
|
|
|
|
|
|
|
ld_s r2, [r1, __tNANO_fiber_OFFSET]
|
|
|
|
|
|
|
|
st_s r2, [r1, __tNANO_current_OFFSET]
|
|
|
|
ld_s r3, [r2, __tTCS_link_OFFSET]
|
|
|
|
st_s r3, [r1, __tNANO_fiber_OFFSET]
|
|
|
|
|
|
|
|
/* clear AE bit to forget this was an exception */
|
|
|
|
lr r3, [_ARC_V2_STATUS32]
|
|
|
|
and r3,r3,(~_ARC_V2_STATUS32_AE)
|
|
|
|
kflag r3
|
|
|
|
/* pretend priority 1 int happened to use common handler */
|
|
|
|
lr r3, [_ARC_V2_AUX_IRQ_ACT]
|
|
|
|
or r3,r3,2
|
|
|
|
sr r3, [_ARC_V2_AUX_IRQ_ACT]
|
|
|
|
|
|
|
|
/* Assumption: r2 has current thread */
|
|
|
|
b _rirq_common_interrupt_swap
|
|
|
|
#else
|
|
|
|
/* Nanokernel-only just returns from exception */
|
|
|
|
|
2015-11-17 14:08:45 -08:00
|
|
|
/* if _Fault returns, restore the registers */
|
|
|
|
_pop_irq_stack_frame
|
|
|
|
|
|
|
|
/* now restore the stack */
|
|
|
|
ld sp,[saved_stack_pointer]
|
|
|
|
rtie
|
arc: trap handler, used by irq_offload, now handles thread switch
It was found that the test latency_measure, when compiled
for microkernel, would fail on the ARC. This because the
trap handler, used by irq_offload, wasn't supporting thread switching.
This submission adds the code to do that, and the code size is
bigger only when CONFIG_MICROKERNEL is defined.
To keep code a bit smaller, there is a trick exploited here where
the AE bit is cleared in the STATUS32 register and in AUX_IRQ_ACT,
bit 1 is set, to make it appear as if the machine has interrupted
at priority 1 level. It then can jump into some common interrupt
exit code for regular interrupts and perform an RTIE instruction
to switch into the new thread.
test/latency_measure/microkernel now passes.
Change-Id: I1872a80bb09a259814540567f51721203201679a
Signed-off-by: Chuck Jordan <cjordan@synopsys.com>
2016-05-26 10:39:20 -07:00
|
|
|
#endif
|
|
|
|
|
2015-11-17 14:08:45 -08:00
|
|
|
#endif /* CONFIG_IRQ_OFFLOAD */
|