1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018/10/28 Bernard The unify RISC-V porting code.
9 * 2021-02-11 lizhirui add gp support
10 * 2021-11-19 JasonHu add fpu support
11 */
12
13 #include <rthw.h>
14 #include <rtthread.h>
15
16 #include "cpuport.h"
17 #include "stack.h"
18 #include <sbi.h>
19 #include <encoding.h>
20
21 #ifdef ARCH_RISCV_FPU
22 #define K_SSTATUS_DEFAULT_BASE (SSTATUS_SPP | SSTATUS_SPIE | SSTATUS_SUM | SSTATUS_FS)
23 #else
24 #define K_SSTATUS_DEFAULT_BASE (SSTATUS_SPP | SSTATUS_SPIE | SSTATUS_SUM)
25 #endif
26
27 #ifdef ARCH_RISCV_VECTOR
28 #define K_SSTATUS_DEFAULT (K_SSTATUS_DEFAULT_BASE | SSTATUS_VS)
29 #else
30 #define K_SSTATUS_DEFAULT K_SSTATUS_DEFAULT_BASE
31 #endif
32 #ifdef RT_USING_SMART
33 #include <lwp_arch.h>
34 #endif
35
36 /**
37 * @brief from thread used interrupt context switch
38 *
39 */
40 volatile rt_ubase_t rt_interrupt_from_thread = 0;
41 /**
42 * @brief to thread used interrupt context switch
43 *
44 */
45 volatile rt_ubase_t rt_interrupt_to_thread = 0;
46 /**
47 * @brief flag to indicate context switch in interrupt or not
48 *
49 */
50 volatile rt_ubase_t rt_thread_switch_interrupt_flag = 0;
51
_rt_hw_stack_init(rt_ubase_t * sp,rt_ubase_t ra,rt_ubase_t sstatus)52 void *_rt_hw_stack_init(rt_ubase_t *sp, rt_ubase_t ra, rt_ubase_t sstatus)
53 {
54 rt_hw_switch_frame_t frame = (rt_hw_switch_frame_t)
55 ((rt_ubase_t)sp - sizeof(struct rt_hw_switch_frame));
56
57 rt_memset(frame, 0, sizeof(struct rt_hw_switch_frame));
58
59 frame->regs[RT_HW_SWITCH_CONTEXT_RA] = ra;
60 frame->regs[RT_HW_SWITCH_CONTEXT_SSTATUS] = sstatus;
61
62 return (void *)frame;
63 }
64
rt_hw_cpu_id(void)65 int rt_hw_cpu_id(void)
66 {
67 return 0;
68 }
69
70 /**
71 * This function will initialize thread stack, we assuming
72 * when scheduler restore this new thread, context will restore
73 * an entry to user first application
74 *
75 * s0-s11, ra, sstatus, a0
76 * @param tentry the entry of thread
77 * @param parameter the parameter of entry
78 * @param stack_addr the beginning stack address
79 * @param texit the function will be called when thread exit
80 *
81 * @return stack address
82 */
rt_hw_stack_init(void * tentry,void * parameter,rt_uint8_t * stack_addr,void * texit)83 rt_uint8_t *rt_hw_stack_init(void *tentry,
84 void *parameter,
85 rt_uint8_t *stack_addr,
86 void *texit)
87 {
88 rt_ubase_t *sp = (rt_ubase_t *)stack_addr;
89 // we use a strict alignment requirement for Q extension
90 sp = (rt_ubase_t *)RT_ALIGN_DOWN((rt_ubase_t)sp, 16);
91
92 (*--sp) = (rt_ubase_t)tentry;
93 (*--sp) = (rt_ubase_t)parameter;
94 (*--sp) = (rt_ubase_t)texit;
95 --sp; /* alignment */
96
97 /* compatible to RESTORE_CONTEXT */
98 extern void _rt_thread_entry(void);
99 return (rt_uint8_t *)_rt_hw_stack_init(sp, (rt_ubase_t)_rt_thread_entry, K_SSTATUS_DEFAULT);
100 }
101
102 /*
103 * #ifdef RT_USING_SMP
104 * void rt_hw_context_switch_interrupt(void *context, rt_ubase_t from, rt_ubase_t to, struct rt_thread *to_thread);
105 * #else
106 * void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to);
107 * #endif
108 */
109 #ifndef RT_USING_SMP
rt_hw_context_switch_interrupt(rt_ubase_t from,rt_ubase_t to,rt_thread_t from_thread,rt_thread_t to_thread)110 void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to, rt_thread_t from_thread, rt_thread_t to_thread)
111 {
112 if (rt_thread_switch_interrupt_flag == 0)
113 rt_interrupt_from_thread = from;
114
115 rt_interrupt_to_thread = to;
116 rt_thread_switch_interrupt_flag = 1;
117
118 return;
119 }
120 #endif /* end of RT_USING_SMP */
121
122 /** shutdown CPU */
rt_hw_cpu_shutdown(void)123 void rt_hw_cpu_shutdown(void)
124 {
125 rt_uint32_t level;
126 rt_kprintf("shutdown...\n");
127
128 level = rt_hw_interrupt_disable();
129
130 sbi_shutdown();
131
132 while (1)
133 ;
134 }
135
rt_hw_set_process_id(int pid)136 void rt_hw_set_process_id(int pid)
137 {
138 // TODO
139 }
140