xref: /haiku/headers/private/system/arch/riscv64/arch_cpu_defs.h (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
1 /*
2  * Copyright 2021, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 #ifndef _SYSTEM_ARCH_RISCV64_DEFS_H
6 #define _SYSTEM_ARCH_RISCV64_DEFS_H
7 
8 
9 #include <SupportDefs.h>
10 
11 #define B_ALWAYS_INLINE __attribute__((always_inline)) inline
12 
13 
14 #ifdef __cplusplus
15 
16 enum {
17 	modeU = 0,
18 	modeS = 1,
19 	modeM = 3,
20 };
21 
22 // fs, xs
23 enum {
24 	extStatusOff     = 0,
25 	extStatusInitial = 1,
26 	extStatusClean   = 2,
27 	extStatusDirty   = 3,
28 };
29 
30 union MstatusReg {
31 	struct {
32 		uint64 ie:      4; // interrupt enable
33 		uint64 pie:     4; // previous interrupt enable
34 		uint64 spp:     1; // previous mode (supervisor)
35 		uint64 unused1: 2;
36 		uint64 mpp:     2; // previous mode (machine)
37 		uint64 fs:      2; // FPU status
38 		uint64 xs:      2; // extensions status
39 		uint64 mprv:    1; // modify privilege
40 		uint64 sum:     1; // permit supervisor user memory access
41 		uint64 mxr:     1; // make executable readable
42 		uint64 tvm:     1; // trap virtual memory
43 		uint64 tw:      1; // timeout wait (trap WFI)
44 		uint64 tsr:     1; // trap SRET
45 		uint64 unused2: 9;
46 		uint64 uxl:     2; // U-mode XLEN
47 		uint64 sxl:     2; // S-mode XLEN
48 		uint64 unused3: 27;
49 		uint64 sd:      1; // status dirty
50 	};
51 	uint64 val;
52 };
53 
54 union SstatusReg {
55 	struct {
56 		uint64 ie:      2; // interrupt enable
57 		uint64 unused1: 2;
58 		uint64 pie:     2; // previous interrupt enable
59 		uint64 unused2: 2;
60 		uint64 spp:     1; // previous mode (supervisor)
61 		uint64 unused3: 4;
62 		uint64 fs:      2; // FPU status
63 		uint64 xs:      2; // extensions status
64 		uint64 unused4: 1;
65 		uint64 sum:     1; // permit supervisor user memory access
66 		uint64 mxr:     1; // make executable readable
67 		uint64 unused5: 12;
68 		uint64 uxl:     2; // U-mode XLEN
69 		uint64 unused6: 29;
70 		uint64 sd:      1; // status dirty
71 	};
72 	uint64 val;
73 };
74 
75 enum {
76 	softInt    = 0,
77 	uSoftInt   = softInt + modeU,
78 	sSoftInt   = softInt + modeS,
79 	mSoftInt   = softInt + modeM,
80 	timerInt   = 4,
81 	uTimerInt  = timerInt + modeU,
82 	sTimerInt  = timerInt + modeS,
83 	mTimerInt  = timerInt + modeM,
84 	externInt  = 8,
85 	uExternInt = externInt + modeU,
86 	sExternInt = externInt + modeS,
87 	mExternInt = externInt + modeM,
88 };
89 
90 enum {
91 	causeInterrupt        = 1ULL << 63, // rest bits are interrupt number
92 	causeExecMisalign     = 0,
93 	causeExecAccessFault  = 1,
94 	causeIllegalInst      = 2,
95 	causeBreakpoint       = 3,
96 	causeLoadMisalign     = 4,
97 	causeLoadAccessFault  = 5,
98 	causeStoreMisalign    = 6,
99 	causeStoreAccessFault = 7,
100 	causeECall            = 8,
101 	causeUEcall           = causeECall + modeU,
102 	causeSEcall           = causeECall + modeS,
103 	causeMEcall           = causeECall + modeM,
104 	causeExecPageFault    = 12,
105 	causeLoadPageFault    = 13,
106 	causeStorePageFault   = 15,
107 };
108 
109 // physical memory protection
110 enum {
111 	pmpR = 0,
112 	pmpW = 1,
113 	pmpX = 2,
114 };
115 
116 enum {
117 	// naturally aligned power of two
118 	pmpMatchNapot = 3 << 3,
119 };
120 
121 enum {
122 	pageBits = 12,
123 	pteCount = 512,
124 	pteIdxBits = 9,
125 };
126 
127 union Pte {
128 	struct {
129 		uint64 isValid:    1;
130 		uint64 isRead:     1;
131 		uint64 isWrite:    1;
132 		uint64 isExec:     1;
133 		uint64 isUser:     1;
134 		uint64 isGlobal:   1;
135 		uint64 isAccessed: 1;
136 		uint64 isDirty:    1;
137 
138 		uint64 rsw:        2;
139 		uint64 ppn:       44;
140 		uint64 reserved:  10;
141 	};
142 	uint64 val;
143 };
144 
145 enum {
146 	satpModeBare =  0,
147 	satpModeSv39 =  8,
148 	satpModeSv48 =  9,
149 	satpModeSv57 = 10,
150 	satpModeSv64 = 11,
151 };
152 
153 union SatpReg {
154 	struct {
155 		uint64 ppn:  44;
156 		uint64 asid: 16;
157 		uint64 mode:  4;
158 	};
159 	uint64 val;
160 };
161 
162 static B_ALWAYS_INLINE uint64 VirtAdrPte(uint64 physAdr, uint32 level)
163 {
164 	return (physAdr >> (pageBits + pteIdxBits*level)) % (1 << pteIdxBits);
165 }
166 
167 static B_ALWAYS_INLINE uint64 VirtAdrOfs(uint64 physAdr)
168 {
169 	return physAdr % PAGESIZE;
170 }
171 
172 #define CSR_REG_MACRO(Name, value) \
173 	static B_ALWAYS_INLINE uint64 Name() { \
174 		uint64 x; asm volatile("csrr %0, " #value : "=r" (x)); return x;} \
175 	static B_ALWAYS_INLINE void Set##Name(uint64 x) { \
176 		asm volatile("csrw " #value ", %0" : : "r" (x));} \
177 	static B_ALWAYS_INLINE void SetBits##Name(uint64 x) { \
178 		asm volatile("csrs " #value ", %0" : : "r" (x));} \
179 	static B_ALWAYS_INLINE void ClearBits##Name(uint64 x) { \
180 		asm volatile("csrc " #value ", %0" : : "r" (x));} \
181 	static B_ALWAYS_INLINE uint64 GetAndSetBits##Name(uint64 x) { \
182 		uint64 res; \
183 		asm volatile("csrrs %0, " #value ", %1" : "=r" (res) : "r" (x)); \
184 		return res; \
185 	} \
186 	static B_ALWAYS_INLINE uint64 GetAndClearBits##Name(uint64 x) { \
187 		uint64 res; \
188 		asm volatile("csrrc %0, " #value ", %1" : "=r" (res) : "r" (x)); \
189 		return res; \
190 	} \
191 
192 // CPU core ID
193 CSR_REG_MACRO(Mhartid, mhartid)
194 
195 // status register
196 CSR_REG_MACRO(Mstatus, mstatus)
197 CSR_REG_MACRO(Sstatus, sstatus)
198 
199 // exception program counter
200 CSR_REG_MACRO(Mepc, mepc)
201 CSR_REG_MACRO(Sepc, sepc)
202 
203 // interrupt pending
204 CSR_REG_MACRO(Mip, mip)
205 CSR_REG_MACRO(Sip, sip)
206 
207 // interrupt enable
208 CSR_REG_MACRO(Mie, mie)
209 CSR_REG_MACRO(Sie, sie)
210 
211 // exception delegation
212 CSR_REG_MACRO(Medeleg, medeleg)
213 // interrupt delegation
214 CSR_REG_MACRO(Mideleg, mideleg)
215 
216 // trap vector, 2 low bits: mode
217 CSR_REG_MACRO(Mtvec, mtvec)
218 CSR_REG_MACRO(Stvec, stvec)
219 
220 // address translation and protection (pointer to page table and flags)
221 CSR_REG_MACRO(Satp, satp)
222 
223 // scratch register
224 CSR_REG_MACRO(Mscratch, mscratch)
225 CSR_REG_MACRO(Sscratch, sscratch)
226 
227 // trap cause
228 CSR_REG_MACRO(Mcause, mcause)
229 CSR_REG_MACRO(Scause, scause)
230 
231 // trap value
232 CSR_REG_MACRO(Mtval, mtval)
233 CSR_REG_MACRO(Stval, stval)
234 
235 // machine-mode counter enable
236 CSR_REG_MACRO(Mcounteren, mcounteren)
237 
238 // cycle counter
239 CSR_REG_MACRO(CpuMcycle, mcycle)
240 CSR_REG_MACRO(CpuCycle, cycle)
241 // monotonic timer
242 CSR_REG_MACRO(CpuTime, time)
243 
244 // physical memory protection
245 CSR_REG_MACRO(Pmpaddr0, pmpaddr0)
246 CSR_REG_MACRO(Pmpcfg0, pmpcfg0)
247 
248 // flush the TLB
249 static B_ALWAYS_INLINE void FlushTlbAll() {
250 	asm volatile("sfence.vma" : : : "memory");}
251 static B_ALWAYS_INLINE void FlushTlbPage(uint64 x) {
252 	asm volatile("sfence.vma %0" : : "r" (x) : "memory");}
253 static B_ALWAYS_INLINE void FlushTlbAllAsid(uint64 asid) {
254 	asm volatile("sfence.vma x0, %0" : : "r" (asid) : "memory");}
255 static B_ALWAYS_INLINE void FlushTlbPageAsid(uint64 page, uint64 asid) {
256 	asm volatile("sfence.vma %0, %1" : : "r" (page), "r" (asid) : "memory");}
257 
258 // flush instruction cache
259 static B_ALWAYS_INLINE void FenceI() {
260 	asm volatile("fence.i" : : : "memory");}
261 
262 static B_ALWAYS_INLINE uint64 Sp() {
263 	uint64 x; asm volatile("mv %0, sp" : "=r" (x)); return x;}
264 static B_ALWAYS_INLINE void SetSp(uint64 x) {
265 	asm volatile("mv sp, %0" : : "r" (x));}
266 static B_ALWAYS_INLINE uint64 Fp() {
267 	uint64 x; asm volatile("mv %0, fp" : "=r" (x)); return x;}
268 static B_ALWAYS_INLINE void SetFp(uint64 x) {
269 	asm volatile("mv fp, %0" : : "r" (x));}
270 static B_ALWAYS_INLINE uint64 Tp() {
271 	uint64 x; asm volatile("mv %0, tp" : "=r" (x)); return x;}
272 static B_ALWAYS_INLINE void SetTp(uint64 x) {
273 	asm volatile("mv tp, %0" : : "r" (x));}
274 static B_ALWAYS_INLINE uint64 Ra() {
275 	uint64 x; asm volatile("mv %0, ra" : "=r" (x)); return x;}
276 static B_ALWAYS_INLINE void SetRa(uint64 x) {
277 	asm volatile("mv ra, %0" : : "r" (x));}
278 
279 static B_ALWAYS_INLINE void Ecall() {asm volatile("ecall");}
280 
281 // Wait for interrupts, reduce CPU load when inactive.
282 static B_ALWAYS_INLINE void Wfi() {asm volatile("wfi");}
283 
284 static B_ALWAYS_INLINE void Mret() {asm volatile("mret");}
285 static B_ALWAYS_INLINE void Sret() {asm volatile("sret");}
286 
287 #endif // __cplusplus
288 
289 
290 #define SPINLOCK_PAUSE()	do {} while (false)
291 
292 
293 #endif	/* _SYSTEM_ARCH_RISCV64_DEFS_H */
294 
295