1 /*
2 * Copyright (c) 2015 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #pragma once
9
10 #include <lk/compiler.h>
11 #include <arch/defines.h>
12 #include <arch/riscv/asm.h>
13
14 #define RISCV_USER_OFFSET (0u)
15 #define RISCV_SUPER_OFFSET (1u)
16 #define RISCV_HYPER_OFFSET (2u)
17 #define RISCV_MACH_OFFSET (3u)
18
19 #if RISCV_M_MODE
20 # define RISCV_XMODE_OFFSET (RISCV_MACH_OFFSET)
21 # define RISCV_XRET mret
22 # define RISCV_MODE_PREFIX m
23 #elif RISCV_S_MODE
24 # define RISCV_XMODE_OFFSET (RISCV_SUPER_OFFSET)
25 # define RISCV_XRET sret
26 # define RISCV_MODE_PREFIX s
27 #else
28 # error Unrecognized RISC-V privilege level selected
29 #endif
30
31 #define RISCV_CSR_XMODE_BITS (RISCV_XMODE_OFFSET << 8)
32
33 // These CSRs are only in user CSR space (still readable by all modes though)
34 #define RISCV_CSR_CYCLE (0xc00)
35 #define RISCV_CSR_TIME (0xc01)
36 #define RISCV_CSR_INSRET (0xc02)
37 #define RISCV_CSR_CYCLEH (0xc80)
38 #define RISCV_CSR_TIMEH (0xc81)
39 #define RISCV_CSR_INSRETH (0xc82)
40
41 // CSRs that exist in both machine and supervisor mode. Synthesize the appropriate
42 // one based on prefixing the name with either m or s.
43 #define RISCV_CSR_XSTATUS __CONCAT(RISCV_MODE_PREFIX, status)
44 #define RISCV_CSR_XIE __CONCAT(RISCV_MODE_PREFIX, ie)
45 #define RISCV_CSR_XTVEC __CONCAT(RISCV_MODE_PREFIX, tvec)
46 #define RISCV_CSR_XSCRATCH __CONCAT(RISCV_MODE_PREFIX, scratch)
47 #define RISCV_CSR_XEPC __CONCAT(RISCV_MODE_PREFIX, epc)
48 #define RISCV_CSR_XCAUSE __CONCAT(RISCV_MODE_PREFIX, cause)
49 #define RISCV_CSR_XTVAL __CONCAT(RISCV_MODE_PREFIX, tval)
50 #define RISCV_CSR_XIP __CONCAT(RISCV_MODE_PREFIX, ip)
51
52 #if RISCV_M_MODE // Machine-mode only CSRs
53 #define RISCV_CSR_MCYCLE (0xb00)
54 #define RISCV_CSR_MVENDORID (0xf11)
55 #define RISCV_CSR_MARCHID (0xf12)
56 #define RISCV_CSR_MIMPID (0xf13)
57 #define RISCV_CSR_MHARTID (0xf14)
58 #define RISCV_CSR_MISA (0x301)
59 #endif // RISCV_M_MODE
60
61 #if RISCV_S_MODE // Supervisor-mode only CSRs
62 #define RISCV_CSR_SATP satp
63 // sstc feature
64 #define RISCV_CSR_STIMECMP (0x14d)
65 #define RISCV_CSR_STIMECMPH (0x15d)
66 #endif
67
68 #define RISCV_CSR_XSTATUS_IE (1ul << (RISCV_XMODE_OFFSET + 0))
69 #define RISCV_CSR_XSTATUS_PIE (1ul << (RISCV_XMODE_OFFSET + 4))
70 #define RISCV_CSR_XSTATUS_SPP (1ul << 8)
71 #define RISCV_CSR_XSTATUS_SUM (1ul << 18)
72 #define RISCV_CSR_XSTATUS_MXR (1ul << 19)
73 #define RISCV_CSR_XSTATUS_SD (1ul << (__riscv_xlen - 1))
74 // Vector state field
75 #define RISCV_CSR_XSTATUS_VS_SHIFT (9)
76 #define RISCV_CSR_XSTATUS_VS_MASK (3ul << RISCV_CSR_XSTATUS_VS_SHIFT)
77 #define RISCV_CSR_XSTATUS_VS_OFF (0ul << RISCV_CSR_XSTATUS_VS_SHIFT)
78 #define RISCV_CSR_XSTATUS_VS_INITIAL (1ul << RISCV_CSR_XSTATUS_VS_SHIFT)
79 #define RISCV_CSR_XSTATUS_VS_CLEAN (2ul << RISCV_CSR_XSTATUS_VS_SHIFT)
80 #define RISCV_CSR_XSTATUS_VS_DIRTY (3ul << RISCV_CSR_XSTATUS_VS_SHIFT)
81 // Floating point state field
82 #define RISCV_CSR_XSTATUS_FS_SHIFT (13)
83 #define RISCV_CSR_XSTATUS_FS_MASK (3ul << RISCV_CSR_XSTATUS_FS_SHIFT)
84 #define RISCV_CSR_XSTATUS_FS_OFF (0ul << RISCV_CSR_XSTATUS_FS_SHIFT)
85 #define RISCV_CSR_XSTATUS_FS_INITIAL (1ul << RISCV_CSR_XSTATUS_FS_SHIFT)
86 #define RISCV_CSR_XSTATUS_FS_CLEAN (2ul << RISCV_CSR_XSTATUS_FS_SHIFT)
87 #define RISCV_CSR_XSTATUS_FS_DIRTY (3ul << RISCV_CSR_XSTATUS_FS_SHIFT)
88 // Extended state field
89 #define RISCV_CSR_XSTATUS_XS_SHIFT (15)
90 #define RISCV_CSR_XSTATUS_XS_MASK (3ul << RISCV_CSR_XSTATUS_XS_SHIFT)
91 #define RISCV_CSR_XSTATUS_XS_OFF (0ul << RISCV_CSR_XSTATUS_XS_SHIFT)
92 #define RISCV_CSR_XSTATUS_XS_INITIAL (1ul << RISCV_CSR_XSTATUS_XS_SHIFT)
93 #define RISCV_CSR_XSTATUS_XS_CLEAN (2ul << RISCV_CSR_XSTATUS_XS_SHIFT)
94 #define RISCV_CSR_XSTATUS_XS_DIRTY (3ul << RISCV_CSR_XSTATUS_XS_SHIFT)
95
96 #define RISCV_CSR_XIE_SIE (1ul << (RISCV_XMODE_OFFSET + 0))
97 #define RISCV_CSR_XIE_TIE (1ul << (RISCV_XMODE_OFFSET + 4))
98 #define RISCV_CSR_XIE_EIE (1ul << (RISCV_XMODE_OFFSET + 8))
99
100 #define RISCV_CSR_XIP_SIP (1ul << (RISCV_XMODE_OFFSET + 0))
101 #define RISCV_CSR_XIP_TIP (1ul << (RISCV_XMODE_OFFSET + 4))
102 #define RISCV_CSR_XIP_EIP (1ul << (RISCV_XMODE_OFFSET + 8))
103
104 // Interrupts, top bit set in cause register
105 #define RISCV_INTERRUPT_USWI 0 // software interrupt
106 #define RISCV_INTERRUPT_SSWI 1
107 #define RISCV_INTERRUPT_MSWI 3
108 #define RISCV_INTERRUPT_UTIM 4 // timer interrupt
109 #define RISCV_INTERRUPT_STIM 5
110 #define RISCV_INTERRUPT_MTIM 7
111 #define RISCV_INTERRUPT_UEXT 8 // external interrupt
112 #define RISCV_INTERRUPT_SEXT 9
113 #define RISCV_INTERRUPT_MEXT 11
114
115 // The 3 interupts above, for the current mode
116 #define RISCV_INTERRUPT_XSWI (RISCV_XMODE_OFFSET)
117 #define RISCV_INTERRUPT_XTIM (4 + RISCV_XMODE_OFFSET)
118 #define RISCV_INTERRUPT_XEXT (8 + RISCV_XMODE_OFFSET)
119
120 // Exceptions
121 #define RISCV_EXCEPTION_IADDR_MISALIGN 0
122 #define RISCV_EXCEPTION_IACCESS_FAULT 1
123 #define RISCV_EXCEPTION_ILLEGAL_INS 2
124 #define RISCV_EXCEPTION_BREAKPOINT 3
125 #define RISCV_EXCEPTION_LOAD_ADDR_MISALIGN 4
126 #define RISCV_EXCEPTION_LOAD_ACCESS_FAULT 5
127 #define RISCV_EXCEPTION_STORE_ADDR_MISALIGN 6
128 #define RISCV_EXCEPTION_STORE_ACCESS_FAULT 7
129 #define RISCV_EXCEPTION_ENV_CALL_U_MODE 8
130 #define RISCV_EXCEPTION_ENV_CALL_S_MODE 9
131 #define RISCV_EXCEPTION_ENV_CALL_M_MODE 11
132 #define RISCV_EXCEPTION_INS_PAGE_FAULT 12
133 #define RISCV_EXCEPTION_LOAD_PAGE_FAULT 13
134 #define RISCV_EXCEPTION_STORE_PAGE_FAULT 15
135
136 #ifndef ASSEMBLY
137 #define ___ASM_STR(x) #x
138 #define __ASM_STR(x) ___ASM_STR(x)
139
140 __BEGIN_CDECLS
141
142 #define riscv_csr_clear(csr, bits) \
143 ({ \
144 ulong __val = bits; \
145 __asm__ volatile( \
146 "csrc " __ASM_STR(csr) ", %0" \
147 :: "rK" (__val) \
148 : "memory"); \
149 })
150
151 #define riscv_csr_read_clear(csr, bits) \
152 ({ \
153 ulong __val = bits; \
154 ulong __val_out; \
155 __asm__ volatile( \
156 "csrrc %0, " __ASM_STR(csr) ", %1" \
157 : "=r"(__val_out) \
158 : "rK" (__val) \
159 : "memory"); \
160 __val_out; \
161 })
162
163 #define riscv_csr_set(csr, bits) \
164 ({ \
165 ulong __val = bits; \
166 __asm__ volatile( \
167 "csrs " __ASM_STR(csr) ", %0" \
168 :: "rK" (__val) \
169 : "memory"); \
170 })
171
172 #define riscv_csr_read(csr) \
173 ({ \
174 ulong __val; \
175 __asm__ volatile( \
176 "csrr %0, " __ASM_STR(csr) \
177 : "=r" (__val) \
178 :: "memory"); \
179 __val; \
180 })
181
182 #define riscv_csr_write(csr, val) \
183 ({ \
184 ulong __val = (ulong)(val); \
185 __asm__ volatile( \
186 "csrw " __ASM_STR(csr) ", %0" \
187 :: "rK" (__val) \
188 : "memory"); \
189 __val; \
190 })
191
192 #include <arch/riscv/iframe.h>
193
194 struct riscv_percpu {
195 // must be first field in the struct
196 struct thread *curr_thread;
197 unsigned int cpu_num;
198 unsigned int hart_id;
199 } __ALIGNED(CACHE_LINE);
200
201 // percpu pointer is held in the tp register while in the kernel
riscv_get_percpu(void)202 static inline struct riscv_percpu *riscv_get_percpu(void) {
203 struct riscv_percpu *cpu;
204 __asm__ volatile("mv %0, tp" : "=&r"(cpu));
205 return cpu;
206 }
207
riscv_set_percpu(struct riscv_percpu * cpu)208 static inline void riscv_set_percpu(struct riscv_percpu *cpu) {
209 __asm__ volatile("mv tp, %0" :: "r"(cpu));
210 }
211
212 // current thread is always at the start of the percpu struct
riscv_get_current_thread(void)213 static inline struct thread *riscv_get_current_thread(void) {
214 struct thread *t;
215 #if __riscv_xlen == 32
216 __asm__ volatile("lw %0, 0(tp)" : "=&r"(t));
217 #else
218 __asm__ volatile("ld %0, 0(tp)" : "=&r"(t));
219 #endif
220 return t;
221 }
222
riscv_set_current_thread(struct thread * t)223 static inline void riscv_set_current_thread(struct thread *t) {
224 #if __riscv_xlen == 32
225 __asm__ volatile("sw %0, 0(tp)" :: "r"(t));
226 #else
227 __asm__ volatile("sd %0, 0(tp)" :: "r"(t));
228 #endif
229 }
230
riscv_current_hart(void)231 static inline uint riscv_current_hart(void) {
232 #if RISCV_M_MODE
233 return riscv_csr_read(RISCV_CSR_MHARTID);
234 #else
235 return riscv_get_percpu()->hart_id;
236 #endif
237 }
238
239 // Platform should pass in a list of secondary harts to start, not
240 // including the boot hart. Will be trimmed to SMP_MAX_CPUS - 1.
241 // Machine mode will always get all of the secondaries released (for now).
242 void riscv_set_secondary_harts_to_start(const uint *harts, size_t count);
243
244 void riscv_exception_entry(void);
245 enum handler_return riscv_timer_exception(void);
246 enum handler_return riscv_software_exception(void);
247 enum handler_return riscv_platform_irq(void);
248 void riscv_syscall_handler(struct riscv_short_iframe *frame);
249
250 // If using S mode, time seems to be implemented in clint.h
251 // TODO: clean up by moving into its own header
252 #if RISCV_S_MODE
253 # if __riscv_xlen == 32
riscv_get_time(void)254 static inline uint64_t riscv_get_time(void) {
255 uint32_t hi, lo;
256
257 do {
258 hi = riscv_csr_read(RISCV_CSR_TIMEH);
259 lo = riscv_csr_read(RISCV_CSR_TIME);
260 } while (hi != riscv_csr_read(RISCV_CSR_TIMEH));
261
262 return (((uint64_t)hi << 32) | lo);
263 }
264 # else
riscv_get_time(void)265 static inline uint64_t riscv_get_time(void) {
266 return riscv_csr_read(RISCV_CSR_TIME);
267 }
268 # endif
269 #endif
270
271 __END_CDECLS
272
273 #endif /* ASSEMBLY */
274