blob: b355fda0c1dfc86eff717d04934097a651575387 [file] [log] [blame]
/*
* Copyright (c) 2019 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _MACRO_PRIV_INC_
#define _MACRO_PRIV_INC_
#ifdef _ASMLANGUAGE
/**
* @brief Save volatile registers
*
* Save the volatile registers and x30 on the process stack. This is
* needed if the thread is switched out because they can be clobbered by the
* ISR and/or context switch.
*
* @return N/A
*/
.macro z_arm64_enter_exc xreg0, xreg1, xreg2
/*
* Two things can happen:
*
* - No context-switch: in this case x19-x28 are callee-saved register
* so we can be sure they are not going to be clobbered by ISR.
* - Context-switch: the callee-saved registers are saved by
* z_arm64_pendsv() in the kernel structure.
*/
stp x0, x1, [sp, #-16]!
stp x2, x3, [sp, #-16]!
stp x4, x5, [sp, #-16]!
stp x6, x7, [sp, #-16]!
stp x8, x9, [sp, #-16]!
stp x10, x11, [sp, #-16]!
stp x12, x13, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x18, x30, [sp, #-16]!
/*
* Store SPSR_ELn and ELR_ELn. This is needed to support nested
* exception handlers
*/
switch_el \xreg0, 3f, 2f, 1f
3:
mrs \xreg1, spsr_el3
mrs \xreg2, elr_el3
b 0f
2:
mrs \xreg1, spsr_el2
mrs \xreg2, elr_el2
b 0f
1:
mrs \xreg1, spsr_el1
mrs \xreg2, elr_el1
0:
stp \xreg1, \xreg2, [sp, #-16]!
.endm
/**
* @brief Restore volatile registers and x30
*
* This is the common exit point for z_arm64_pendsv() and _isr_wrapper(). We
* restore the registers saved on the process stack including X30. The return
* address used by eret (in ELR_ELn) is either restored by z_arm64_pendsv() if
* a context-switch happened or not touched at all by the ISR if there was no
* context-switch.
*
* @return N/A
*/
.macro z_arm64_exit_exc xreg0, xreg1, xreg2
/*
* Restore SPSR_ELn and ELR_ELn. This is needed to support nested
* exception handlers
*/
ldp \xreg0, \xreg1, [sp], #16
switch_el \xreg2, 3f, 2f, 1f
3:
msr spsr_el3, \xreg0
msr elr_el3, \xreg1
b 0f
2:
msr spsr_el2, \xreg0
msr elr_el2, \xreg1
b 0f
1:
msr spsr_el1, \xreg0
msr elr_el1, \xreg1
0:
/*
* In x30 we can have:
*
* - The address of irq_unlock() in swap.c when swapping in a thread
* that was cooperatively swapped out (used by ret in
* z_arm64_call_svc())
* - A previos generic value if the thread that we are swapping in was
* swapped out preemptively by the ISR.
*/
ldp x18, x30, [sp], #16
ldp x16, x17, [sp], #16
ldp x14, x15, [sp], #16
ldp x12, x13, [sp], #16
ldp x10, x11, [sp], #16
ldp x8, x9, [sp], #16
ldp x6, x7, [sp], #16
ldp x4, x5, [sp], #16
ldp x2, x3, [sp], #16
ldp x0, x1, [sp], #16
/*
* In general in the ELR_ELn register we can find:
*
* - The address of ret in z_arm64_call_svc() in case of arch_swap()
* (see swap.c)
* - The address of the next instruction at the time of the IRQ when the
* thread was switched out.
* - The address of z_thread_entry() for new threads (see thread.c).
*/
eret
.endm
#endif /* _ASMLANGUAGE */
#endif /* _MACRO_PRIV_INC_ */