arch : arc: clean up of assembly codes
* update comments to match latest codes * add extra comments for some assembly, macros * use macro to replace duplcated codes * remove unused codes, lables, symobols Signed-off-by: Wayne Ren <wei.ren@synopsys.com>
This commit is contained in:
parent
3f88ddd549
commit
84cdfa271d
6 changed files with 196 additions and 213 deletions
|
@ -19,7 +19,6 @@
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
|
|
||||||
GTEXT(_Fault)
|
GTEXT(_Fault)
|
||||||
GTEXT(z_do_kernel_oops)
|
|
||||||
GTEXT(__reset)
|
GTEXT(__reset)
|
||||||
GTEXT(__memory_error)
|
GTEXT(__memory_error)
|
||||||
GTEXT(__instruction_error)
|
GTEXT(__instruction_error)
|
||||||
|
@ -38,6 +37,17 @@ GTEXT(__ev_maligned)
|
||||||
GTEXT(z_irq_do_offload);
|
GTEXT(z_irq_do_offload);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
.macro _save_exc_regs_into_stack
|
||||||
|
#ifdef CONFIG_ARC_HAS_SECURE
|
||||||
|
/* ERSEC_STAT is IOW/RAZ in normal mode */
|
||||||
|
lr r0,[_ARC_V2_ERSEC_STAT]
|
||||||
|
st_s r0, [sp, ___isf_t_sec_stat_OFFSET]
|
||||||
|
#endif
|
||||||
|
lr r0,[_ARC_V2_ERET]
|
||||||
|
st_s r0, [sp, ___isf_t_pc_OFFSET]
|
||||||
|
lr r0,[_ARC_V2_ERSTATUS]
|
||||||
|
st_s r0, [sp, ___isf_t_status32_OFFSET]
|
||||||
|
.endm
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The exception handling will use top part of interrupt stack to
|
* The exception handling will use top part of interrupt stack to
|
||||||
|
@ -89,15 +99,7 @@ _exc_entry:
|
||||||
*/
|
*/
|
||||||
_create_irq_stack_frame
|
_create_irq_stack_frame
|
||||||
|
|
||||||
#ifdef CONFIG_ARC_HAS_SECURE
|
_save_exc_regs_into_stack
|
||||||
/* ERSEC_STAT is IOW/RAZ in normal mode */
|
|
||||||
lr r0,[_ARC_V2_ERSEC_STAT]
|
|
||||||
st_s r0, [sp, ___isf_t_sec_stat_OFFSET]
|
|
||||||
#endif
|
|
||||||
lr r0,[_ARC_V2_ERSTATUS]
|
|
||||||
st_s r0, [sp, ___isf_t_status32_OFFSET]
|
|
||||||
lr r0,[_ARC_V2_ERET]
|
|
||||||
st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */
|
|
||||||
|
|
||||||
/* sp is parameter of _Fault */
|
/* sp is parameter of _Fault */
|
||||||
mov_s r0, sp
|
mov_s r0, sp
|
||||||
|
@ -174,10 +176,13 @@ _exc_return:
|
||||||
mov r2, ilink
|
mov r2, ilink
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Assumption: r2 has next thread */
|
/* Assumption: r2 has next thread */
|
||||||
b _rirq_newthread_switch
|
b _rirq_newthread_switch
|
||||||
|
|
||||||
_exc_return_from_exc:
|
_exc_return_from_exc:
|
||||||
|
/* exception handler may change return address.
|
||||||
|
* reload it
|
||||||
|
*/
|
||||||
ld_s r0, [sp, ___isf_t_pc_OFFSET]
|
ld_s r0, [sp, ___isf_t_pc_OFFSET]
|
||||||
sr r0, [_ARC_V2_ERET]
|
sr r0, [_ARC_V2_ERET]
|
||||||
|
|
||||||
|
@ -185,7 +190,7 @@ _exc_return_from_exc:
|
||||||
mov_s sp, ilink
|
mov_s sp, ilink
|
||||||
rtie
|
rtie
|
||||||
|
|
||||||
|
/* separated entry for trap which may be used by irq_offload, USERPSACE */
|
||||||
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap)
|
SECTION_SUBSEC_FUNC(TEXT,__fault,__ev_trap)
|
||||||
/* get the id of trap_s */
|
/* get the id of trap_s */
|
||||||
lr ilink, [_ARC_V2_ECR]
|
lr ilink, [_ARC_V2_ECR]
|
||||||
|
@ -208,15 +213,12 @@ valid_syscall_id:
|
||||||
*/
|
*/
|
||||||
_create_irq_stack_frame
|
_create_irq_stack_frame
|
||||||
|
|
||||||
#ifdef CONFIG_ARC_SECURE_FIRMWARE
|
_save_exc_regs_into_stack
|
||||||
/* ERSEC_STAT is IOW/RAZ in normal mode */
|
|
||||||
lr r0, [_ARC_V2_ERSEC_STAT]
|
/* exc return and do sys call in kernel mode,
|
||||||
st_s r0, [sp, ___isf_t_sec_stat_OFFSET]
|
* so need to clear U bit, r0 is already loaded
|
||||||
#endif
|
* with ERSTATUS in _save_exc_regs_into_stack
|
||||||
lr r0,[_ARC_V2_ERET]
|
*/
|
||||||
st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */
|
|
||||||
lr r0,[_ARC_V2_ERSTATUS]
|
|
||||||
st_s r0, [sp, ___isf_t_status32_OFFSET]
|
|
||||||
|
|
||||||
bclr r0, r0, _ARC_V2_STATUS32_U_BIT
|
bclr r0, r0, _ARC_V2_STATUS32_U_BIT
|
||||||
sr r0, [_ARC_V2_ERSTATUS]
|
sr r0, [_ARC_V2_ERSTATUS]
|
||||||
|
@ -239,15 +241,7 @@ _do_non_syscall_trap:
|
||||||
/* save caller saved registers */
|
/* save caller saved registers */
|
||||||
_create_irq_stack_frame
|
_create_irq_stack_frame
|
||||||
|
|
||||||
#ifdef CONFIG_ARC_HAS_SECURE
|
_save_exc_regs_into_stack
|
||||||
lr r0,[_ARC_V2_ERSEC_STAT]
|
|
||||||
st_s r0, [sp, ___isf_t_sec_stat_OFFSET]
|
|
||||||
#endif
|
|
||||||
lr r0,[_ARC_V2_ERSTATUS]
|
|
||||||
st_s r0, [sp, ___isf_t_status32_OFFSET]
|
|
||||||
lr r0,[_ARC_V2_ERET]
|
|
||||||
st_s r0, [sp, ___isf_t_pc_OFFSET] /* eret into pc */
|
|
||||||
|
|
||||||
|
|
||||||
/* check whether irq stack is used */
|
/* check whether irq stack is used */
|
||||||
_check_and_inc_int_nest_counter r0, r1
|
_check_and_inc_int_nest_counter r0, r1
|
||||||
|
@ -266,6 +260,8 @@ exc_nest_handle:
|
||||||
_dec_int_nest_counter r0, r1
|
_dec_int_nest_counter r0, r1
|
||||||
|
|
||||||
_pop_irq_stack_frame
|
_pop_irq_stack_frame
|
||||||
|
|
||||||
|
/* ERSTATUS, ERET are not changed, so ok to rtie */
|
||||||
rtie
|
rtie
|
||||||
#endif /* CONFIG_IRQ_OFFLOAD */
|
#endif /* CONFIG_IRQ_OFFLOAD */
|
||||||
b _exc_entry
|
b _exc_entry
|
||||||
|
|
|
@ -35,37 +35,35 @@ _rirq_enter/_firq_enter: they are jump points.
|
||||||
The flow is the following:
|
The flow is the following:
|
||||||
|
|
||||||
ISR -> _isr_wrapper -- + -> _rirq_enter -> _isr_demux -> ISR -> _rirq_exit
|
ISR -> _isr_wrapper -- + -> _rirq_enter -> _isr_demux -> ISR -> _rirq_exit
|
||||||
|
|
|
|
||||||
+ -> _firq_enter -> _isr_demux -> ISR -> _firq_exit
|
+ -> _firq_enter -> _isr_demux -> ISR -> _firq_exit
|
||||||
|
|
||||||
Context switch explanation:
|
Context switch explanation:
|
||||||
|
|
||||||
The context switch code is spread in these files:
|
The context switch code is spread in these files:
|
||||||
|
|
||||||
isr_wrapper.s, switch.s, swap_macros.s, fast_irq.s, regular_irq.s
|
isr_wrapper.s, switch.s, swap_macros.h, fast_irq.s, regular_irq.s
|
||||||
|
|
||||||
IRQ stack frame layout:
|
IRQ stack frame layout:
|
||||||
|
|
||||||
high address
|
high address
|
||||||
|
|
||||||
status32
|
status32
|
||||||
pc
|
pc
|
||||||
lp_count
|
lp_count
|
||||||
lp_start
|
lp_start
|
||||||
lp_end
|
lp_end
|
||||||
blink
|
blink
|
||||||
r13
|
r13
|
||||||
...
|
...
|
||||||
sp -> r0
|
sp -> r0
|
||||||
|
|
||||||
low address
|
low address
|
||||||
|
|
||||||
The context switch code adopts this standard so that it is easier to follow:
|
The context switch code adopts this standard so that it is easier to follow:
|
||||||
|
|
||||||
- r1 contains _kernel ASAP and is not overwritten over the lifespan of
|
- r2 contains _kernel.current ASAP, and the incoming thread when we
|
||||||
the functions.
|
transition from outgoing thread to incoming thread
|
||||||
- r2 contains _kernel.current ASAP, and the incoming thread when we
|
|
||||||
transition from outgoing thread to incoming thread
|
|
||||||
|
|
||||||
Not loading _kernel into r0 allows loading _kernel without stomping on
|
Not loading _kernel into r0 allows loading _kernel without stomping on
|
||||||
the parameter in r0 in arch_switch().
|
the parameter in r0 in arch_switch().
|
||||||
|
@ -100,47 +98,49 @@ done upfront, and the rest is done when needed:
|
||||||
|
|
||||||
o RIRQ
|
o RIRQ
|
||||||
|
|
||||||
All needed registers to run C code in the ISR are saved automatically
|
All needed registers to run C code in the ISR are saved automatically
|
||||||
on the outgoing thread's stack: loop, status32, pc, and the caller-
|
on the outgoing thread's stack: loop, status32, pc, and the caller-
|
||||||
saved GPRs. That stack frame layout is pre-determined. If returning
|
saved GPRs. That stack frame layout is pre-determined. If returning
|
||||||
to a thread, the stack is popped and no registers have to be saved by
|
to a thread, the stack is popped and no registers have to be saved by
|
||||||
the kernel. If a context switch is required, the callee-saved GPRs
|
the kernel. If a context switch is required, the callee-saved GPRs
|
||||||
are then saved in the thread control structure (TCS).
|
are then saved in the thread's stack.
|
||||||
|
|
||||||
o FIRQ
|
o FIRQ
|
||||||
|
|
||||||
First, a FIRQ can be interrupting a lower-priority RIRQ: if this is the case,
|
First, a FIRQ can be interrupting a lower-priority RIRQ: if this is
|
||||||
the FIRQ does not take a scheduling decision and leaves it the RIRQ to
|
the case, the FIRQ does not take a scheduling decision and leaves it
|
||||||
handle. This limits the amount of code that has to run at interrupt-level.
|
the RIRQ to handle. This limits the amount of code that has to run at
|
||||||
|
interrupt-level.
|
||||||
|
|
||||||
CONFIG_RGF_NUM_BANKS==1 case:
|
CONFIG_RGF_NUM_BANKS==1 case:
|
||||||
Registers are saved on the stack frame just as they are for RIRQ.
|
Registers are saved on the stack frame just as they are for RIRQ.
|
||||||
Context switch can happen just as it does in the RIRQ case, however,
|
Context switch can happen just as it does in the RIRQ case, however,
|
||||||
if the FIRQ interrupted a RIRQ, the FIRQ will return from interrupt and
|
if the FIRQ interrupted a RIRQ, the FIRQ will return from interrupt
|
||||||
let the RIRQ do the context switch. At entry, one register is needed in order
|
and let the RIRQ do the context switch. At entry, one register is
|
||||||
to have code to save other registers. r0 is saved first in a global called
|
needed in order to have code to save other registers. r0 is saved
|
||||||
saved_r0.
|
first in the stack and restored later
|
||||||
|
|
||||||
CONFIG_RGF_NUM_BANKS!=1 case:
|
CONFIG_RGF_NUM_BANKS!=1 case:
|
||||||
During early initialization, the sp in the 2nd register bank is made to
|
During early initialization, the sp in the 2nd register bank is made to
|
||||||
refer to _firq_stack. This allows for the FIRQ handler to use its own stack.
|
refer to _firq_stack. This allows for the FIRQ handler to use its own
|
||||||
GPRs are banked, loop registers are saved in unused callee saved regs upon
|
stack. GPRs are banked, loop registers are saved in unused callee saved
|
||||||
interrupt entry. If returning to a thread, loop registers are restored and the
|
regs upon interrupt entry. If returning to a thread, loop registers are
|
||||||
CPU switches back to bank 0 for the GPRs. If a context switch is
|
restored and the CPU switches back to bank 0 for the GPRs. If a context
|
||||||
needed, at this point only are all the registers saved. First, a
|
switch is needed, at this point only are all the registers saved.
|
||||||
stack frame with the same layout as the automatic RIRQ one is created
|
First, a stack frame with the same layout as the automatic RIRQ one is
|
||||||
and then the callee-saved GPRs are saved in the TCS. status32_p0 and
|
created and then the callee-saved GPRs are saved in the stack.
|
||||||
ilink are saved in this case, not status32 and pc.
|
status32_p0 and ilink are saved in this case, not status32 and pc.
|
||||||
To create the stack frame, the FIRQ handling code must first go back to using
|
To create the stack frame, the FIRQ handling code must first go back to
|
||||||
bank0 of registers, since that is where the registers containing the exiting
|
using bank0 of registers, since that is where the registers containing
|
||||||
thread are saved. Care must be taken not to touch any register before saving
|
the exiting thread are saved. Care must be taken not to touch any
|
||||||
them: the only one usable at that point is the stack pointer.
|
register before saving them: the only one usable at that point is the
|
||||||
|
stack pointer.
|
||||||
|
|
||||||
o coop
|
o coop
|
||||||
|
|
||||||
When a coop context switch is done, the callee-saved registers are
|
When a coop context switch is done, the callee-saved registers are
|
||||||
saved in the TCS. The other GPRs do not need to be saved, since the
|
saved in the stack. The other GPRs do not need to be saved, since the
|
||||||
compiler has already placed them on the stack.
|
compiler has already placed them on the stack.
|
||||||
|
|
||||||
For restoring the contexts, there are six cases. In all cases, the
|
For restoring the contexts, there are six cases. In all cases, the
|
||||||
callee-saved registers of the incoming thread have to be restored. Then, there
|
callee-saved registers of the incoming thread have to be restored. Then, there
|
||||||
|
@ -148,57 +148,56 @@ are specifics for each case:
|
||||||
|
|
||||||
From coop:
|
From coop:
|
||||||
|
|
||||||
o to coop
|
o to coop
|
||||||
|
|
||||||
Do a normal function call return.
|
Do a normal function call return.
|
||||||
|
|
||||||
o to any irq
|
o to any irq
|
||||||
|
|
||||||
The incoming interrupted thread has an IRQ stack frame containing the
|
The incoming interrupted thread has an IRQ stack frame containing the
|
||||||
caller-saved registers that has to be popped. status32 has to be restored,
|
caller-saved registers that has to be popped. status32 has to be
|
||||||
then we jump to the interrupted instruction.
|
restored, then we jump to the interrupted instruction.
|
||||||
|
|
||||||
From FIRQ:
|
From FIRQ:
|
||||||
|
|
||||||
When CONFIG_RGF_NUM_BANKS==1, context switch is done as it is for RIRQ.
|
When CONFIG_RGF_NUM_BANKS==1, context switch is done as it is for RIRQ.
|
||||||
When CONFIG_RGF_NUM_BANKS!=1, the processor is put back to using bank0,
|
When CONFIG_RGF_NUM_BANKS!=1, the processor is put back to using bank0,
|
||||||
not bank1 anymore, because it had to save the outgoing context from bank0,
|
not bank1 anymore, because it had to save the outgoing context from
|
||||||
and now has to load the incoming one
|
bank0, and now has to load the incoming one into bank0.
|
||||||
into bank0.
|
|
||||||
|
|
||||||
o to coop
|
o to coop
|
||||||
|
|
||||||
The address of the returning instruction from arch_switch() is loaded
|
The address of the returning instruction from arch_switch() is loaded
|
||||||
in ilink and the saved status32 in status32_p0.
|
in ilink and the saved status32 in status32_p0.
|
||||||
|
|
||||||
o to any irq
|
o to any irq
|
||||||
|
|
||||||
The IRQ has saved the caller-saved registers in a stack frame, which must be
|
The IRQ has saved the caller-saved registers in a stack frame, which
|
||||||
popped, and status32 and pc loaded in status32_p0 and ilink.
|
must be popped, and status32 and pc loaded in status32_p0 and ilink.
|
||||||
|
|
||||||
From RIRQ:
|
From RIRQ:
|
||||||
|
|
||||||
o to coop
|
o to coop
|
||||||
|
|
||||||
The interrupt return mechanism in the processor expects a stack frame, but
|
The interrupt return mechanism in the processor expects a stack frame,
|
||||||
the outgoing context did not create one. A fake one is created here, with
|
but the outgoing context did not create one. A fake one is created
|
||||||
only the relevant values filled in: pc, status32.
|
here, with only the relevant values filled in: pc, status32.
|
||||||
|
|
||||||
There is a discrepancy between the ABI from the ARCv2 docs, including the
|
There is a discrepancy between the ABI from the ARCv2 docs,
|
||||||
way the processor pushes GPRs in pairs in the IRQ stack frame, and the ABI
|
including the way the processor pushes GPRs in pairs in the IRQ stack
|
||||||
GCC uses. r13 should be a callee-saved register, but GCC treats it as
|
frame, and the ABI GCC uses. r13 should be a callee-saved register,
|
||||||
caller-saved. This means that the processor pushes it in the stack frame
|
but GCC treats it as caller-saved. This means that the processor pushes
|
||||||
along with r12, but the compiler does not save it before entering a
|
it in the stack frame along with r12, but the compiler does not save it
|
||||||
function. So, it is saved as part of the callee-saved registers, and
|
before entering a function. So, it is saved as part of the callee-saved
|
||||||
restored there, but the processor restores it _a second time_ when popping
|
registers, and restored there, but the processor restores it _a second
|
||||||
the IRQ stack frame. Thus, the correct value must also be put in the fake
|
time_ when popping the IRQ stack frame. Thus, the correct value must
|
||||||
stack frame when returning to a thread that context switched out
|
also be put in the fake stack frame when returning to a thread that
|
||||||
cooperatively.
|
context switched out cooperatively.
|
||||||
|
|
||||||
o to any irq
|
o to any irq
|
||||||
|
|
||||||
Both types of IRQs already have an IRQ stack frame: simply return from
|
Both types of IRQs already have an IRQ stack frame: simply return from
|
||||||
interrupt.
|
interrupt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SECTION_FUNC(TEXT, _isr_wrapper)
|
SECTION_FUNC(TEXT, _isr_wrapper)
|
||||||
|
@ -251,8 +250,6 @@ GTEXT(sys_trace_isr_enter)
|
||||||
#if defined(CONFIG_SYS_POWER_MANAGEMENT)
|
#if defined(CONFIG_SYS_POWER_MANAGEMENT)
|
||||||
.macro exit_tickless_idle
|
.macro exit_tickless_idle
|
||||||
clri r0 /* do not interrupt exiting tickless idle operations */
|
clri r0 /* do not interrupt exiting tickless idle operations */
|
||||||
push_s r1
|
|
||||||
push_s r0
|
|
||||||
mov_s r1, _kernel
|
mov_s r1, _kernel
|
||||||
ld_s r0, [r1, _kernel_offset_to_idle] /* requested idle duration */
|
ld_s r0, [r1, _kernel_offset_to_idle] /* requested idle duration */
|
||||||
breq r0, 0, _skip_sys_power_save_idle_exit
|
breq r0, 0, _skip_sys_power_save_idle_exit
|
||||||
|
@ -263,8 +260,6 @@ GTEXT(sys_trace_isr_enter)
|
||||||
pop_s blink
|
pop_s blink
|
||||||
|
|
||||||
_skip_sys_power_save_idle_exit:
|
_skip_sys_power_save_idle_exit:
|
||||||
pop_s r0
|
|
||||||
pop_s r1
|
|
||||||
seti r0
|
seti r0
|
||||||
.endm
|
.endm
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -25,17 +25,6 @@ GTEXT(_rirq_enter)
|
||||||
GTEXT(_rirq_exit)
|
GTEXT(_rirq_exit)
|
||||||
GTEXT(_rirq_newthread_switch)
|
GTEXT(_rirq_newthread_switch)
|
||||||
|
|
||||||
|
|
||||||
#if 0 /* TODO: when FIRQ is not present, all would be regular */
|
|
||||||
#define NUM_REGULAR_IRQ_PRIO_LEVELS CONFIG_NUM_IRQ_PRIO_LEVELS
|
|
||||||
#else
|
|
||||||
#define NUM_REGULAR_IRQ_PRIO_LEVELS (CONFIG_NUM_IRQ_PRIO_LEVELS-1)
|
|
||||||
#endif
|
|
||||||
/* note: the above define assumes that prio 0 IRQ is for FIRQ, and
|
|
||||||
* that all others are regular interrupts.
|
|
||||||
* TODO: Revist this if FIRQ becomes configurable.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
===========================================================
|
===========================================================
|
||||||
|
@ -214,23 +203,16 @@ will be corrupted.
|
||||||
|
|
||||||
SECTION_FUNC(TEXT, _rirq_enter)
|
SECTION_FUNC(TEXT, _rirq_enter)
|
||||||
|
|
||||||
|
/* the ISR will be handled in separate interrupt stack,
|
||||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
* so stack checking must be diabled, or exception will
|
||||||
#ifdef CONFIG_ARC_SECURE_FIRMWARE
|
* be caused
|
||||||
lr r2, [_ARC_V2_SEC_STAT]
|
*/
|
||||||
bclr r2, r2, _ARC_V2_SEC_STAT_SSC_BIT
|
_disable_stack_checking r2
|
||||||
sflag r2
|
|
||||||
|
|
||||||
#else
|
|
||||||
/* disable stack checking */
|
|
||||||
lr r2, [_ARC_V2_STATUS32]
|
|
||||||
bclr r2, r2, _ARC_V2_STATUS32_SC_BIT
|
|
||||||
kflag r2
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
clri
|
clri
|
||||||
|
|
||||||
/* check whether irq stack is used */
|
/* check whether irq stack is used, if
|
||||||
|
* not switch to isr stack
|
||||||
|
*/
|
||||||
_check_and_inc_int_nest_counter r0, r1
|
_check_and_inc_int_nest_counter r0, r1
|
||||||
|
|
||||||
bne.d rirq_nest
|
bne.d rirq_nest
|
||||||
|
@ -302,6 +284,9 @@ _rirq_newthread_switch:
|
||||||
.balign 4
|
.balign 4
|
||||||
_rirq_switch_from_coop:
|
_rirq_switch_from_coop:
|
||||||
|
|
||||||
|
/* for a cooperative switch, it's not in irq, so
|
||||||
|
* need to set some regs for irq return
|
||||||
|
*/
|
||||||
_set_misc_regs_irq_switch_from_coop
|
_set_misc_regs_irq_switch_from_coop
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -96,18 +96,10 @@ SECTION_FUNC(TEXT, arch_switch)
|
||||||
|
|
||||||
_store_old_thread_callee_regs
|
_store_old_thread_callee_regs
|
||||||
|
|
||||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
|
||||||
/* disable stack checking here, as sp will be changed to target
|
/* disable stack checking here, as sp will be changed to target
|
||||||
* thread'sp
|
* thread'sp
|
||||||
*/
|
*/
|
||||||
#if defined(CONFIG_ARC_HAS_SECURE) && defined(CONFIG_ARC_SECURE_FIRMWARE)
|
_disable_stack_checking r3
|
||||||
bclr r3, r3, _ARC_V2_SEC_STAT_SSC_BIT
|
|
||||||
sflag r3
|
|
||||||
#else
|
|
||||||
bclr r3, r3, _ARC_V2_STATUS32_SC_BIT
|
|
||||||
kflag r3
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mov_s r2, r0
|
mov_s r2, r0
|
||||||
|
|
||||||
|
@ -134,9 +126,12 @@ _switch_return_from_coop:
|
||||||
kflag r3 /* write status32 */
|
kflag r3 /* write status32 */
|
||||||
|
|
||||||
#ifdef CONFIG_EXECUTION_BENCHMARKING
|
#ifdef CONFIG_EXECUTION_BENCHMARKING
|
||||||
b _capture_value_for_benchmarking
|
push_s blink
|
||||||
#endif
|
|
||||||
return_loc:
|
bl read_timer_end_of_swap
|
||||||
|
|
||||||
|
pop_s blink
|
||||||
|
#endif /* CONFIG_EXECUTION_BENCHMARKING */
|
||||||
j_s [blink]
|
j_s [blink]
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,14 +162,3 @@ _switch_return_from_firq:
|
||||||
sr r3, [_ARC_V2_AUX_IRQ_ACT]
|
sr r3, [_ARC_V2_AUX_IRQ_ACT]
|
||||||
#endif
|
#endif
|
||||||
rtie
|
rtie
|
||||||
|
|
||||||
#ifdef CONFIG_EXECUTION_BENCHMARKING
|
|
||||||
.balign 4
|
|
||||||
_capture_value_for_benchmarking:
|
|
||||||
push_s blink
|
|
||||||
|
|
||||||
bl read_timer_end_of_swap
|
|
||||||
|
|
||||||
pop_s blink
|
|
||||||
b return_loc
|
|
||||||
#endif /* CONFIG_EXECUTION_BENCHMARKING */
|
|
||||||
|
|
|
@ -93,22 +93,13 @@ SECTION_FUNC(TEXT, z_arc_userspace_enter)
|
||||||
/*
|
/*
|
||||||
* In ARCv2, the U bit can only be set through exception return
|
* In ARCv2, the U bit can only be set through exception return
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
|
||||||
/* disable stack checking as the stack should be initialized */
|
/* disable stack checking as the stack should be initialized */
|
||||||
#ifdef CONFIG_ARC_SECURE_FIRMWARE
|
_disable_stack_checking blink
|
||||||
lr blink, [_ARC_V2_SEC_STAT]
|
|
||||||
bclr blink, blink, _ARC_V2_SEC_STAT_SSC_BIT
|
|
||||||
sflag blink
|
|
||||||
#else
|
|
||||||
lr blink, [_ARC_V2_STATUS32]
|
|
||||||
bclr blink, blink, _ARC_V2_STATUS32_SC_BIT
|
|
||||||
kflag blink
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
/* the end of user stack in r5 */
|
/* the end of user stack in r5 */
|
||||||
add r5, r4, r5
|
add r5, r4, r5
|
||||||
/* start of privilege stack */
|
/* start of privilege stack */
|
||||||
add blink, r5, CONFIG_PRIVILEGED_STACK_SIZE+STACK_GUARD_SIZE
|
add blink, r5, CONFIG_PRIVILEGED_STACK_SIZE + STACK_GUARD_SIZE
|
||||||
mov_s sp, r5
|
mov_s sp, r5
|
||||||
|
|
||||||
push_s r0
|
push_s r0
|
||||||
|
@ -118,6 +109,9 @@ SECTION_FUNC(TEXT, z_arc_userspace_enter)
|
||||||
|
|
||||||
mov r5, sp /* skip r0, r1, r2, r3 */
|
mov r5, sp /* skip r0, r1, r2, r3 */
|
||||||
|
|
||||||
|
/* to avoid the leakage of kernel info, the thread stack needs to be
|
||||||
|
* re-initialized
|
||||||
|
*/
|
||||||
#ifdef CONFIG_INIT_STACKS
|
#ifdef CONFIG_INIT_STACKS
|
||||||
mov_s r0, 0xaaaaaaaa
|
mov_s r0, 0xaaaaaaaa
|
||||||
#else
|
#else
|
||||||
|
@ -128,23 +122,22 @@ _clear_user_stack:
|
||||||
cmp r4, r5
|
cmp r4, r5
|
||||||
jlt _clear_user_stack
|
jlt _clear_user_stack
|
||||||
|
|
||||||
|
/* reload the stack checking regs as the original kernel stack
|
||||||
|
* becomess user stack
|
||||||
|
*/
|
||||||
#ifdef CONFIG_ARC_STACK_CHECKING
|
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||||
mov_s r1, _kernel
|
mov_s r1, _kernel
|
||||||
ld_s r2, [r1, _kernel_offset_to_current]
|
ld_s r2, [r1, _kernel_offset_to_current]
|
||||||
|
|
||||||
_load_stack_check_regs
|
_load_stack_check_regs
|
||||||
|
|
||||||
#ifdef CONFIG_ARC_SECURE_FIRMWARE
|
_enable_stack_checking r0
|
||||||
lr r0, [_ARC_V2_SEC_STAT]
|
|
||||||
bset r0, r0, _ARC_V2_SEC_STAT_SSC_BIT
|
|
||||||
sflag r0
|
|
||||||
#else
|
|
||||||
lr r0, [_ARC_V2_STATUS32]
|
|
||||||
bset r0, r0, _ARC_V2_STATUS32_SC_BIT
|
|
||||||
kflag r0
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* the following codes are used to switch from kernel mode
|
||||||
|
* to user mode by fake exception, because U bit can only be set
|
||||||
|
* by exception
|
||||||
|
*/
|
||||||
_arc_go_to_user_space:
|
_arc_go_to_user_space:
|
||||||
lr r0, [_ARC_V2_STATUS32]
|
lr r0, [_ARC_V2_STATUS32]
|
||||||
bset r0, r0, _ARC_V2_STATUS32_U_BIT
|
bset r0, r0, _ARC_V2_STATUS32_U_BIT
|
||||||
|
@ -185,9 +178,8 @@ _arc_go_to_user_space:
|
||||||
mov_s blink, 0
|
mov_s blink, 0
|
||||||
|
|
||||||
#ifdef CONFIG_EXECUTION_BENCHMARKING
|
#ifdef CONFIG_EXECUTION_BENCHMARKING
|
||||||
b _capture_value_for_benchmarking_userspace
|
bl read_timer_end_of_userspace_enter
|
||||||
return_loc_userspace_enter:
|
#endif
|
||||||
#endif /* CONFIG_EXECUTION_BENCHMARKING */
|
|
||||||
|
|
||||||
rtie
|
rtie
|
||||||
|
|
||||||
|
@ -298,20 +290,3 @@ inc_len:
|
||||||
/* increment length measurement, loop again */
|
/* increment length measurement, loop again */
|
||||||
add_s r0, r0, 1
|
add_s r0, r0, 1
|
||||||
b_s strlen_loop
|
b_s strlen_loop
|
||||||
|
|
||||||
#ifdef CONFIG_EXECUTION_BENCHMARKING
|
|
||||||
.balign 4
|
|
||||||
_capture_value_for_benchmarking_userspace:
|
|
||||||
mov r1, _kernel
|
|
||||||
ld_s r2, [r1, _kernel_offset_to_current]
|
|
||||||
_save_callee_saved_regs
|
|
||||||
push_s blink
|
|
||||||
|
|
||||||
bl read_timer_end_of_userspace_enter
|
|
||||||
|
|
||||||
pop_s blink
|
|
||||||
mov r1, _kernel
|
|
||||||
ld_s r2, [r1, _kernel_offset_to_current]
|
|
||||||
_load_callee_saved_regs
|
|
||||||
b return_loc_userspace_enter
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
#ifdef _ASMLANGUAGE
|
#ifdef _ASMLANGUAGE
|
||||||
|
|
||||||
/* entering this macro, current is in r2 */
|
/* save callee regs of current thread in r2 */
|
||||||
.macro _save_callee_saved_regs
|
.macro _save_callee_saved_regs
|
||||||
|
|
||||||
sub_s sp, sp, ___callee_saved_stack_t_SIZEOF
|
sub_s sp, sp, ___callee_saved_stack_t_SIZEOF
|
||||||
|
@ -89,7 +89,7 @@
|
||||||
st sp, [r2, _thread_offset_to_sp]
|
st sp, [r2, _thread_offset_to_sp]
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
/* entering this macro, current is in r2 */
|
/* load the callee regs of thread (in r2)*/
|
||||||
.macro _load_callee_saved_regs
|
.macro _load_callee_saved_regs
|
||||||
/* restore stack pointer from struct k_thread */
|
/* restore stack pointer from struct k_thread */
|
||||||
ld sp, [r2, _thread_offset_to_sp]
|
ld sp, [r2, _thread_offset_to_sp]
|
||||||
|
@ -162,6 +162,7 @@
|
||||||
|
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
/* discard callee regs */
|
||||||
.macro _discard_callee_saved_regs
|
.macro _discard_callee_saved_regs
|
||||||
add_s sp, sp, ___callee_saved_stack_t_SIZEOF
|
add_s sp, sp, ___callee_saved_stack_t_SIZEOF
|
||||||
.endm
|
.endm
|
||||||
|
@ -265,7 +266,7 @@
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To use this macor, r2 should have the value of thread struct pointer to
|
* To use this macro, r2 should have the value of thread struct pointer to
|
||||||
* _kernel.current. r3 is a scratch reg.
|
* _kernel.current. r3 is a scratch reg.
|
||||||
*/
|
*/
|
||||||
.macro _load_stack_check_regs
|
.macro _load_stack_check_regs
|
||||||
|
@ -297,6 +298,7 @@
|
||||||
/* check and increase the interrupt nest counter
|
/* check and increase the interrupt nest counter
|
||||||
* after increase, check whether nest counter == 1
|
* after increase, check whether nest counter == 1
|
||||||
* the result will be EQ bit of status32
|
* the result will be EQ bit of status32
|
||||||
|
* two temp regs are needed
|
||||||
*/
|
*/
|
||||||
.macro _check_and_inc_int_nest_counter reg1 reg2
|
.macro _check_and_inc_int_nest_counter reg1 reg2
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
@ -316,7 +318,10 @@
|
||||||
cmp \reg2, 1
|
cmp \reg2, 1
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
/* decrease interrupt nest counter */
|
/* decrease interrupt stack nest counter
|
||||||
|
* the counter > 0, interrupt stack is used, or
|
||||||
|
* not used
|
||||||
|
*/
|
||||||
.macro _dec_int_nest_counter reg1 reg2
|
.macro _dec_int_nest_counter reg1 reg2
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
_get_cpu_id \reg1
|
_get_cpu_id \reg1
|
||||||
|
@ -336,6 +341,7 @@
|
||||||
|
|
||||||
/* If multi bits in IRQ_ACT are set, i.e. last bit != fist bit, it's
|
/* If multi bits in IRQ_ACT are set, i.e. last bit != fist bit, it's
|
||||||
* in nest interrupt. The result will be EQ bit of status32
|
* in nest interrupt. The result will be EQ bit of status32
|
||||||
|
* need two temp reg to do this
|
||||||
*/
|
*/
|
||||||
.macro _check_nest_int_by_irq_act reg1, reg2
|
.macro _check_nest_int_by_irq_act reg1, reg2
|
||||||
lr \reg1, [_ARC_V2_AUX_IRQ_ACT]
|
lr \reg1, [_ARC_V2_AUX_IRQ_ACT]
|
||||||
|
@ -349,11 +355,18 @@
|
||||||
cmp \reg1, \reg2
|
cmp \reg1, \reg2
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
/* macro to get id of current cpu
|
||||||
|
* the result will be in reg (a reg)
|
||||||
|
*/
|
||||||
.macro _get_cpu_id reg
|
.macro _get_cpu_id reg
|
||||||
lr \reg, [_ARC_V2_IDENTITY]
|
lr \reg, [_ARC_V2_IDENTITY]
|
||||||
xbfu \reg, \reg, 0xe8
|
xbfu \reg, \reg, 0xe8
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
/* macro to get the interrupt stack of current cpu
|
||||||
|
* the result will be in irq_sp (a reg)
|
||||||
|
*/
|
||||||
.macro _get_curr_cpu_irq_stack irq_sp
|
.macro _get_curr_cpu_irq_stack irq_sp
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
_get_cpu_id \irq_sp
|
_get_cpu_id \irq_sp
|
||||||
|
@ -478,6 +491,41 @@
|
||||||
pop_s r2
|
pop_s r2
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
/* macro to disable stack checking in assembly, need a GPR
|
||||||
|
* to do this
|
||||||
|
*/
|
||||||
|
.macro _disable_stack_checking reg
|
||||||
|
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||||
|
#ifdef CONFIG_ARC_SECURE_FIRMWARE
|
||||||
|
lr \reg, [_ARC_V2_SEC_STAT]
|
||||||
|
bclr \reg, \reg, _ARC_V2_SEC_STAT_SSC_BIT
|
||||||
|
sflag \reg
|
||||||
|
|
||||||
|
#else
|
||||||
|
lr \reg, [_ARC_V2_STATUS32]
|
||||||
|
bclr \reg, \reg, _ARC_V2_STATUS32_SC_BIT
|
||||||
|
kflag \reg
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
.endm
|
||||||
|
|
||||||
|
/* macro to enable stack checking in assembly, need a GPR
|
||||||
|
* to do this
|
||||||
|
*/
|
||||||
|
.macro _enable_stack_checking reg
|
||||||
|
#ifdef CONFIG_ARC_STACK_CHECKING
|
||||||
|
#ifdef CONFIG_ARC_SECURE_FIRMWARE
|
||||||
|
lr \reg, [_ARC_V2_SEC_STAT]
|
||||||
|
bset \reg, \reg, _ARC_V2_SEC_STAT_SSC_BIT
|
||||||
|
sflag \reg
|
||||||
|
#else
|
||||||
|
lr \reg, [_ARC_V2_STATUS32]
|
||||||
|
bset \reg, \reg, _ARC_V2_STATUS32_SC_BIT
|
||||||
|
kflag \reg
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
.endm
|
||||||
|
|
||||||
#endif /* _ASMLANGUAGE */
|
#endif /* _ASMLANGUAGE */
|
||||||
|
|
||||||
#endif /* ZEPHYR_ARCH_ARC_INCLUDE_SWAP_MACROS_H_ */
|
#endif /* ZEPHYR_ARCH_ARC_INCLUDE_SWAP_MACROS_H_ */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue