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