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 #elif RISCV_S_MODE
23 # define RISCV_XMODE_OFFSET (RISCV_SUPER_OFFSET)
24 # define RISCV_XRET sret
25 #else
26 # error Unrecognized RISC-V privilege level selected
27 #endif
28
29 #define RISCV_CSR_XMODE_BITS (RISCV_XMODE_OFFSET << 8)
30
31 // These CSRs are only in user CSR space (still readable by all modes though)
32 #define RISCV_CSR_CYCLE (0xc00)
33 #define RISCV_CSR_TIME (0xc01)
34 #define RISCV_CSR_INSRET (0xc02)
35 #define RISCV_CSR_CYCLEH (0xc80)
36 #define RISCV_CSR_TIMEH (0xc81)
37 #define RISCV_CSR_INSRETH (0xc82)
38
39 #define RISCV_CSR_XSTATUS (0x000 | RISCV_CSR_XMODE_BITS)
40 #define RISCV_CSR_XIE (0x004 | RISCV_CSR_XMODE_BITS)
41 #define RISCV_CSR_XTVEC (0x005 | RISCV_CSR_XMODE_BITS)
42 #define RISCV_CSR_XSCRATCH (0x040 | RISCV_CSR_XMODE_BITS)
43 #define RISCV_CSR_XEPC (0x041 | RISCV_CSR_XMODE_BITS)
44 #define RISCV_CSR_XCAUSE (0x042 | RISCV_CSR_XMODE_BITS)
45 #define RISCV_CSR_XTVAL (0x043 | RISCV_CSR_XMODE_BITS)
46 #define RISCV_CSR_XIP (0x044 | RISCV_CSR_XMODE_BITS)
47
48 #if RISCV_M_MODE // Machine-mode only CSRs
49 #define RISCV_CSR_MCYCLE (0xb00)
50 #define RISCV_CSR_MVENDORID (0xf11)
51 #define RISCV_CSR_MARCHID (0xf12)
52 #define RISCV_CSR_MIMPID (0xf13)
53 #define RISCV_CSR_MHARTID (0xf14)
54 #define RISCV_CSR_MISA (0x301)
55 #endif // RISCV_M_MODE
56
57 #if RISCV_S_MODE // Supervisor-mode only CSRs
58 #define RISCV_CSR_SATP (0x180)
59 #endif
60
61 #define RISCV_CSR_XSTATUS_IE (1ul << (RISCV_XMODE_OFFSET + 0))
62 #define RISCV_CSR_XSTATUS_PIE (1ul << (RISCV_XMODE_OFFSET + 4))
63 #define RISCV_CSR_XSTATUS_SPP (1ul << 8)
64 #define RISCV_CSR_XSTATUS_SUM (1ul << 18)
65 #define RISCV_CSR_XSTATUS_MXR (1ul << 19)
66 #define RISCV_CSR_XSTATUS_FS_SHIFT (13)
67 #define RISCV_CSR_XSTATUS_FS_MASK (3ul << RISCV_CSR_XSTATUS_FS_SHIFT)
68
69 #define RISCV_CSR_XIE_SIE (1ul << (RISCV_XMODE_OFFSET + 0))
70 #define RISCV_CSR_XIE_TIE (1ul << (RISCV_XMODE_OFFSET + 4))
71 #define RISCV_CSR_XIE_EIE (1ul << (RISCV_XMODE_OFFSET + 8))
72
73 #define RISCV_CSR_XIP_SIP (1ul << (RISCV_XMODE_OFFSET + 0))
74 #define RISCV_CSR_XIP_TIP (1ul << (RISCV_XMODE_OFFSET + 4))
75 #define RISCV_CSR_XIP_EIP (1ul << (RISCV_XMODE_OFFSET + 8))
76
77 // Interrupts, top bit set in cause register
78 #define RISCV_INTERRUPT_USWI 0 // software interrupt
79 #define RISCV_INTERRUPT_SSWI 1
80 #define RISCV_INTERRUPT_MSWI 3
81 #define RISCV_INTERRUPT_UTIM 4 // timer interrupt
82 #define RISCV_INTERRUPT_STIM 5
83 #define RISCV_INTERRUPT_MTIM 7
84 #define RISCV_INTERRUPT_UEXT 8 // external interrupt
85 #define RISCV_INTERRUPT_SEXT 9
86 #define RISCV_INTERRUPT_MEXT 11
87
88 // The 3 interupts above, for the current mode
89 #define RISCV_INTERRUPT_XSWI (RISCV_XMODE_OFFSET)
90 #define RISCV_INTERRUPT_XTIM (4 + RISCV_XMODE_OFFSET)
91 #define RISCV_INTERRUPT_XEXT (8 + RISCV_XMODE_OFFSET)
92
93 // Exceptions
94 #define RISCV_EXCEPTION_IADDR_MISALIGN 0
95 #define RISCV_EXCEPTION_IACCESS_FAULT 1
96 #define RISCV_EXCEPTION_ILLEGAL_INS 2
97 #define RISCV_EXCEPTION_BREAKPOINT 3
98 #define RISCV_EXCEPTION_LOAD_ADDR_MISALIGN 4
99 #define RISCV_EXCEPTION_LOAD_ACCESS_FAULT 5
100 #define RISCV_EXCEPTION_STORE_ADDR_MISALIGN 6
101 #define RISCV_EXCEPTION_STORE_ACCESS_FAULT 7
102 #define RISCV_EXCEPTION_ENV_CALL_U_MODE 8
103 #define RISCV_EXCEPTION_ENV_CALL_S_MODE 9
104 #define RISCV_EXCEPTION_ENV_CALL_M_MODE 11
105 #define RISCV_EXCEPTION_INS_PAGE_FAULT 12
106 #define RISCV_EXCEPTION_LOAD_PAGE_FAULT 13
107 #define RISCV_EXCEPTION_STORE_PAGE_FAULT 15
108
109 #ifndef ASSEMBLY
110 #define __ASM_STR(x) #x
111
112 #define riscv_csr_clear(csr, bits) \
113 ({ \
114 ulong __val = bits; \
115 __asm__ volatile( \
116 "csrc " __ASM_STR(csr) ", %0" \
117 :: "rK" (__val) \
118 : "memory"); \
119 })
120
121 #define riscv_csr_read_clear(csr, bits) \
122 ({ \
123 ulong __val = bits; \
124 ulong __val_out; \
125 __asm__ volatile( \
126 "csrrc %0, " __ASM_STR(csr) ", %1" \
127 : "=r"(__val_out) \
128 : "rK" (__val) \
129 : "memory"); \
130 __val_out; \
131 })
132
133 #define riscv_csr_set(csr, bits) \
134 ({ \
135 ulong __val = bits; \
136 __asm__ volatile( \
137 "csrs " __ASM_STR(csr) ", %0" \
138 :: "rK" (__val) \
139 : "memory"); \
140 })
141
142 #define riscv_csr_read(csr) \
143 ({ \
144 ulong __val; \
145 __asm__ volatile( \
146 "csrr %0, " __ASM_STR(csr) \
147 : "=r" (__val) \
148 :: "memory"); \
149 __val; \
150 })
151
152 #define riscv_csr_write(csr, val) \
153 ({ \
154 ulong __val = (ulong)val; \
155 __asm__ volatile( \
156 "csrw " __ASM_STR(csr) ", %0" \
157 :: "rK" (__val) \
158 : "memory"); \
159 __val; \
160 })
161
162 #include <arch/riscv/iframe.h>
163
164 struct riscv_percpu {
165 // must be first field in the struct
166 struct thread *curr_thread;
167 unsigned int cpu_num;
168 unsigned int hart_id;
169 } __ALIGNED(CACHE_LINE);
170
171 // percpu pointer is held in the tp register while in the kernel
riscv_get_percpu(void)172 static inline struct riscv_percpu *riscv_get_percpu(void) {
173 struct riscv_percpu *cpu;
174 __asm__ volatile("mv %0, tp" : "=&r"(cpu));
175 return cpu;
176 }
177
riscv_set_percpu(struct riscv_percpu * cpu)178 static inline void riscv_set_percpu(struct riscv_percpu *cpu) {
179 __asm__ volatile("mv tp, %0" :: "r"(cpu));
180 }
181
182 // current thread is always at the start of the percpu struct
riscv_get_current_thread(void)183 static inline struct thread *riscv_get_current_thread(void) {
184 struct thread *t;
185 #if __riscv_xlen == 32
186 __asm__ volatile("lw %0, 0(tp)" : "=&r"(t));
187 #else
188 __asm__ volatile("ld %0, 0(tp)" : "=&r"(t));
189 #endif
190 return t;
191 }
192
riscv_set_current_thread(struct thread * t)193 static inline void riscv_set_current_thread(struct thread *t) {
194 #if __riscv_xlen == 32
195 __asm__ volatile("sw %0, 0(tp)" :: "r"(t));
196 #else
197 __asm__ volatile("sd %0, 0(tp)" :: "r"(t));
198 #endif
199 }
200
riscv_current_hart(void)201 static inline uint riscv_current_hart(void) {
202 #if RISCV_M_MODE
203 return riscv_csr_read(RISCV_CSR_MHARTID);
204 #else
205 return riscv_get_percpu()->hart_id;
206 #endif
207 }
208
209 void riscv_set_secondary_count(int count);
210
211 void riscv_exception_entry(void);
212 enum handler_return riscv_timer_exception(void);
213 enum handler_return riscv_software_exception(void);
214 enum handler_return riscv_platform_irq(void);
215 void riscv_syscall_handler(struct riscv_short_iframe *frame);
216
217 // If using S mode, time seems to be implemented in clint.h
218 // TODO: clean up by moving into its own header
219 #if RISCV_S_MODE
220 # if __riscv_xlen == 32
riscv_get_time(void)221 static inline uint64_t riscv_get_time(void) {
222 uint32_t hi, lo;
223
224 do {
225 hi = riscv_csr_read(RISCV_CSR_TIMEH);
226 lo = riscv_csr_read(RISCV_CSR_TIME);
227 } while (hi != riscv_csr_read(RISCV_CSR_TIMEH));
228
229 return (((uint64_t)hi << 32) | lo);
230 }
231 # else
riscv_get_time(void)232 static inline uint64_t riscv_get_time(void) {
233 return riscv_csr_read(RISCV_CSR_TIME);
234 }
235 # endif
236 #endif
237
238 #endif /* ASSEMBLY */
239