1/*
2 * Copyright (c) 2022 BayLibre, SAS
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include <zephyr/toolchain.h>
8#include <zephyr/linker/sections.h>
9#include <zephyr/kernel.h>
10#include <zephyr/sys/util.h>
11#include <offsets_short.h>
12#include <zephyr/arch/cpu.h>
13#include "asm_macros.inc"
14
15/* Convenience macros for loading/storing register states. */
16
17#define DO_CALLEE_SAVED(op, reg) \
18	RV_E(	op ra, _thread_offset_to_ra(reg)	);\
19	RV_E(	op s0, _thread_offset_to_s0(reg)	);\
20	RV_E(	op s1, _thread_offset_to_s1(reg)	);\
21	RV_I(	op s2, _thread_offset_to_s2(reg)	);\
22	RV_I(	op s3, _thread_offset_to_s3(reg)	);\
23	RV_I(	op s4, _thread_offset_to_s4(reg)	);\
24	RV_I(	op s5, _thread_offset_to_s5(reg)	);\
25	RV_I(	op s6, _thread_offset_to_s6(reg)	);\
26	RV_I(	op s7, _thread_offset_to_s7(reg)	);\
27	RV_I(	op s8, _thread_offset_to_s8(reg)	);\
28	RV_I(	op s9, _thread_offset_to_s9(reg)	);\
29	RV_I(	op s10, _thread_offset_to_s10(reg)	);\
30	RV_I(	op s11, _thread_offset_to_s11(reg)	)
31
32GTEXT(z_riscv_switch)
33GTEXT(z_thread_mark_switched_in)
34GTEXT(z_riscv_configure_stack_guard)
35GTEXT(z_riscv_fpu_thread_context_switch)
36
37/* void z_riscv_switch(k_thread_t *switch_to, k_thread_t *switch_from) */
38SECTION_FUNC(TEXT, z_riscv_switch)
39
40	/* Save the old thread's callee-saved registers */
41	DO_CALLEE_SAVED(sr, a1)
42
43	/* Save the old thread's stack pointer */
44	sr sp, _thread_offset_to_sp(a1)
45
46	/* Set thread->switch_handle = thread to mark completion */
47	sr a1, ___thread_t_switch_handle_OFFSET(a1)
48
49	/* Get the new thread's stack pointer */
50	lr sp, _thread_offset_to_sp(a0)
51
52#if defined(CONFIG_THREAD_LOCAL_STORAGE)
53	/* Get the new thread's tls pointer */
54	lr tp, _thread_offset_to_tls(a0)
55#endif
56
57#if defined(CONFIG_FPU_SHARING)
58	 /* Preserve a0 across following call. s0 is not yet restored. */
59	mv s0, a0
60	call z_riscv_fpu_thread_context_switch
61	mv a0, s0
62#endif
63
64#if defined(CONFIG_PMP_STACK_GUARD)
65	/* Stack guard has priority over user space for PMP usage. */
66	mv s0, a0
67	call z_riscv_pmp_stackguard_enable
68	mv a0, s0
69#elif defined(CONFIG_USERSPACE)
70	/*
71	 * When stackguard is not enabled, we need to configure the PMP only
72	 * at context switch time as the PMP is not in effect while inm-mode.
73	 * (it is done on every exception return otherwise).
74	 */
75	lb t0, _thread_offset_to_user_options(a0)
76	andi t0, t0, K_USER
77	beqz t0, not_user_task
78	mv s0, a0
79	call z_riscv_pmp_usermode_enable
80	mv a0, s0
81not_user_task:
82#endif
83
84#if CONFIG_INSTRUMENT_THREAD_SWITCHING
85	mv s0, a0
86	call z_thread_mark_switched_in
87	mv a0, s0
88#endif
89
90	/* Restore the new thread's callee-saved registers */
91	DO_CALLEE_SAVED(lr, a0)
92
93	/* Return to arch_switch() or _irq_wrapper() */
94	ret
95