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