summaryrefslogtreecommitdiff
path: root/sys/arch/riscv/include/sysreg.h
blob: 7a1344e1314e99ec9bdfebfe9fcb4eaec598a302 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
/* $NetBSD: sysreg.h,v 1.29 2023/05/07 12:41:48 skrll Exp $ */

/*
 * Copyright (c) 2014 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Matt Thomas of 3am Software Foundry.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _RISCV_SYSREG_H_
#define	_RISCV_SYSREG_H_

#ifndef _KERNEL
#include <sys/param.h>
#endif

#include <riscv/reg.h>

#define	FCSR_FMASK	0	// no exception bits
#define	FCSR_FRM	__BITS(7, 5)
#define	 FCSR_FRM_RNE	0b000	// Round Nearest, ties to Even
#define	 FCSR_FRM_RTZ	0b001	// Round Towards Zero
#define	 FCSR_FRM_RDN	0b010	// Round DowN (-infinity)
#define	 FCSR_FRM_RUP	0b011	// Round UP (+infinity)
#define	 FCSR_FRM_RMM	0b100	// Round to nearest, ties to Max Magnitude
#define	 FCSR_FRM_DYN	0b111	// Dynamic rounding
#define	FCSR_FFLAGS	__BITS(4, 0)	// Sticky bits
#define	FCSR_NV		__BIT(4)	// iNValid operation
#define	FCSR_DZ		__BIT(3)	// Divide by Zero
#define	FCSR_OF		__BIT(2)	// OverFlow
#define	FCSR_UF		__BIT(1)	// UnderFlow
#define	FCSR_NX		__BIT(0)	// iNeXact

static inline uint32_t
fcsr_read(void)
{
	uint32_t __fcsr;
	asm volatile("frcsr %0" : "=r"(__fcsr) :: "memory");
	return __fcsr;
}


static inline uint32_t
fcsr_write(uint32_t __new)
{
	uint32_t __old;
	asm volatile("fscsr %0, %1" : "=r"(__old) : "r"(__new) : "memory");
	return __old;
}

static inline uint32_t
fcsr_fflags_read(void)
{
	uint32_t __old;
	asm volatile("frflags %0" : "=r"(__old) :: "memory");
	return __SHIFTOUT(__old, FCSR_FFLAGS);
}

static inline uint32_t
fcsr_fflags_write(uint32_t __new)
{
	uint32_t __old;
	__new = __SHIFTIN(__new, FCSR_FFLAGS);
	asm volatile("fsflags %0, %1" : "=r"(__old) : "r"(__new) : "memory");
	return __SHIFTOUT(__old, FCSR_FFLAGS);
}

static inline uint32_t
fcsr_frm_read(void)
{
	uint32_t __old;
	asm volatile("frrm\t%0" : "=r"(__old) :: "memory");
	return __SHIFTOUT(__old, FCSR_FRM);
}

static inline uint32_t
fcsr_frm_write(uint32_t __new)
{
	uint32_t __old;
	__new = __SHIFTIN(__new, FCSR_FRM);
	asm volatile("fsrm\t%0, %1" : "=r"(__old) : "r"(__new) : "memory");
	return __SHIFTOUT(__old, FCSR_FRM);
}


#define	RISCVREG_READ_INLINE(regname)					\
static inline uintptr_t							\
csr_##regname##_read(void)						\
{									\
	uintptr_t __rv;							\
	asm volatile("csrr %0, " #regname : "=r"(__rv) :: "memory");	\
	return __rv;							\
}

#define	RISCVREG_WRITE_INLINE(regname)					\
static inline void							\
csr_##regname##_write(uintptr_t __val)					\
{									\
	asm volatile("csrw " #regname ", %0" :: "r"(__val) : "memory");	\
}

#define	RISCVREG_SET_INLINE(regname)					\
static inline void							\
csr_##regname##_set(uintptr_t __mask)					\
{									\
	if (__builtin_constant_p(__mask) && __mask < 0x20) {		\
		asm volatile("csrsi " #regname ", %0" :: "i"(__mask) :	\
		    "memory");						\
	} else {							\
		asm volatile("csrs " #regname ", %0" :: "r"(__mask) :	\
		    "memory");						\
	}								\
}

#define	RISCVREG_CLEAR_INLINE(regname)					\
static inline void							\
csr_##regname##_clear(uintptr_t __mask)					\
{									\
	if (__builtin_constant_p(__mask) && __mask < 0x20) {		\
		asm volatile("csrci " #regname ", %0" :: "i"(__mask) :	\
		    "memory");						\
	} else {							\
		asm volatile("csrc " #regname ", %0" :: "r"(__mask) :	\
		    "memory");						\
	}								\
}

#define	RISCVREG_READ_WRITE_INLINE(regname)				\
RISCVREG_READ_INLINE(regname)						\
RISCVREG_WRITE_INLINE(regname)
#define	RISCVREG_SET_CLEAR_INLINE(regname)				\
RISCVREG_SET_INLINE(regname)						\
RISCVREG_CLEAR_INLINE(regname)
#define	RISCVREG_READ_SET_CLEAR_INLINE(regname)				\
RISCVREG_READ_INLINE(regname)						\
RISCVREG_SET_CLEAR_INLINE(regname)
#define	RISCVREG_READ_WRITE_SET_CLEAR_INLINE(regname)			\
RISCVREG_READ_WRITE_INLINE(regname)					\
RISCVREG_SET_CLEAR_INLINE(regname)

/* Supervisor Status Register */
RISCVREG_READ_SET_CLEAR_INLINE(sstatus)		// supervisor status register
#ifdef _LP64
#define	SR_WPRI		__BITS(62, 34) | __BITS(31, 20) | \
			__BIT(17) | __BITS(12, 11) | __BIT(7) | __BITS(4, 2) | \
			__BIT(0)
#define	SR_SD		__BIT(63)	// any of FS or VS or XS dirty
			/* Bits 62-34 are WPRI */
#define	SR_UXL		__BITS(33, 32)	// U-mode XLEN
#define	 SR_UXL_32	1		//   XLEN ==  32
#define	 SR_UXL_64	2		//   XLEN ==  64
#define	 SR_UXL_128	3		//   XLEN == 128
			/* Bits 31-20 are WPRI*/
#else
#define	SR_WPRI		__BITS(30, 20) | \
			__BIT(17) | __BITS(12, 11) | __BIT(7) | __BITS(4, 2) | \
			__BIT(0)
#define	SR_SD		__BIT(31)	// any of FS or VS or XS dirty
			/* Bits 30-20 are WPRI*/
#endif /* _LP64 */

/* Both RV32 and RV64 have the bottom 20 bits shared */
#define	SR_MXR		__BIT(19)	// Make eXecutable Readable
#define	SR_SUM		__BIT(18)	// permit Supervisor User Memory access
			/* Bit 17 is WPRI */
#define	SR_XS		__BITS(16, 15)	// Vector extension state
#define	 SR_XS_OFF		0	//   All off
#define	 SR_XS_SOME_ON		1	//   None dirty or clean, some on
#define	 SR_XS_SOME_CLEAN	2	//   None dirty, some clean
#define	 SR_XS_SOME_DIRTY	3	//   Some dirty
#define	SR_FS		__BITS(14, 13)	// Floating-point unit state
#define	 SR_FS_OFF	0		//   Off
#define	 SR_FS_INITIAL	1		//   Initial
#define	 SR_FS_CLEAN	2		//   Clean
#define	 SR_FS_DIRTY	3		//   Dirty
			/* Bits 12-11 are WPRI */
#define	SR_VS		__BITS(10, 9)	// User-mode extention state
#define	 SR_VS_OFF	SR_FS_OFF	//   Off
#define	 SR_VS_INITIAL	SR_FS_INITIAL	//   Initial
#define	 SR_VS_CLEAN	SR_FS_CLEAN	//   Clean
#define	 SR_VS_DIRTY	SR_FS_DIRTY	//   Dirty
#define	SR_SPP		__BIT(8)	// Priv level before supervisor mode
			/* Bit 7 is WPRI */
#define	SR_UBE		__BIT(6)	// User-mode endianness
#define	SR_SPIE		__BIT(5)	// S-Mode interrupts enabled before trap
			/* Bits 4-2 are WPRI */
#define	SR_SIE		__BIT(1)	// Supervisor mode interrupt enable
			/* Bit 0 is WPRI */

/* Supervisor interrupt registers */
/* ... interrupt pending register (sip) */
RISCVREG_READ_SET_CLEAR_INLINE(sip)		// supervisor interrupt pending
			/* Bit (XLEN-1) - 10 is WIRI */
#define	SIP_SEIP	__BIT(9)	// S-mode interrupt pending
			/* Bit 8-6 is WIRI */
#define	SIP_STIP	__BIT(5)	// S-mode timer interrupt pending
			/* Bit 4-2 is WIRI */
#define	SIP_SSIP	__BIT(1)	// S-mode software interrupt pending
			/* Bit 0 is WIRI */

/* ... interrupt-enable register (sie) */
RISCVREG_READ_SET_CLEAR_INLINE(sie)		// supervisor interrupt enable
			/* Bit (XLEN-1) - 10 is WIRI */
#define	SIE_SEIE	__BIT(9)	// S-mode interrupt enable
			/* Bit 8-6 is WIRI */
#define	SIE_STIE	__BIT(5)	// S-mode timer interrupt enable
			/* Bit 4-2 is WIRI */
#define	SIE_SSIE	__BIT(1)	// S-mode software interrupt enable
			/* Bit 0 is WIRI */

/* Mask for all interrupts */
#define	SIE_IM		(SIE_SEI | SIE_STIE | SIE_SSIE)	/* XXX unused? */

// U-mode sstatus values
#ifdef _LP64
#define	SR_USER64	(SR_SPIE | __SHIFTIN(SR_UXL_64, SR_UXL))
#define	SR_USER32	(SR_SPIE | __SHIFTIN(SR_UXL_32, SR_UXL))
#else
#define	SR_USER		(SR_SPIE)
#endif

// Cause register
#define	CAUSE_INTERRUPT_P(cause)	((cause) & __BIT(XLEN - 1))
#define	CAUSE_CODE(cause)		((cause) & __BITS(XLEN - 2, 0))

// Cause register - exceptions
#define	CAUSE_FETCH_MISALIGNED		0
#define	CAUSE_FETCH_ACCESS		1
#define	CAUSE_ILLEGAL_INSTRUCTION	2
#define	CAUSE_BREAKPOINT		3
#define	CAUSE_LOAD_MISALIGNED		4
#define	CAUSE_LOAD_ACCESS		5
#define	CAUSE_STORE_MISALIGNED		6
#define	CAUSE_STORE_ACCESS		7
#define	CAUSE_USER_ECALL		8
#define	CAUSE_SYSCALL			CAUSE_USER_ECALL /* convenience alias */
#define	CAUSE_SUPERVISOR_ECALL		9
/* 10 is reserved */
#define	CAUSE_MACHINE_ECALL		11
#define	CAUSE_FETCH_PAGE_FAULT		12
#define	CAUSE_LOAD_PAGE_FAULT		13
/* 14 is Reserved */
#define	CAUSE_STORE_PAGE_FAULT		15
/* >= 16 is reserved/custom */

// Cause register - interrupts
#define	IRQ_SUPERVISOR_SOFTWARE		 1
#define	IRQ_VIRTUAL_SUPERVISOR_SOFTWARE	 2
#define	IRQ_MACHINE_SOFTWARE		 3
#define	IRQ_SUPERVISOR_TIMER		 5
#define	IRQ_VIRTUAL_SUPERVISOR_TIMER	 6
#define	IRQ_MACHINE_TIMER		 7
#define	IRQ_SUPERVISOR_EXTERNAL		 9
#define	IRQ_VIRTUAL_SUPERVISOR_EXTERNAL	10
#define	IRQ_MACHINE_EXTERNAL		11
#define	IRQ_SUPERVISOR_GUEST_EXTERNAL	12
#define IRQ_NSOURCES			16

RISCVREG_READ_INLINE(time)
#ifdef _LP64
RISCVREG_READ_INLINE(cycle)
#else /* !_LP64 */
static inline uint64_t
csr_cycle_read(void)
{
	uint32_t __hi0, __hi1, __lo0;
	do {
		asm volatile(
			"csrr\t%[__hi0], cycleh"
		"\n\t"	"csrr\t%[__lo0], cycle"
		"\n\t"	"csrr\t%[__hi1], cycleh"
		   :	[__hi0] "=r"(__hi0),
			[__lo0] "=r"(__lo0),
			[__hi1] "=r"(__hi1));
	} while (__hi0 != __hi1);
	return
	    __SHIFTIN(__hi0, __BITS(63, 32)) |
	    __SHIFTIN(__lo0, __BITS(31,  0));
}
#endif /* !_LP64 */

#ifdef _LP64
#define	SATP_MODE		__BITS(63, 60)	// Translation mode
#define	 SATP_MODE_BARE		0		//   No translation or protection
				/* modes 1-7 reserved for standard use */
#define	 SATP_MODE_SV39		8		//   Page-based 39-bit virt addr
#define	 SATP_MODE_SV48		9		//   Page-based 48-bit virt addr
#define	 SATP_MODE_SV57		10		//   Page-based 57-bit virt addr
#define	 SATP_MODE_SV64		11		//   Page-based 64-bit virt addr
				/* modes 12-13 reserved for standard use */
				/* modes 14-15 designated for custom use */
#define	SATP_ASID		__BITS(59, 44)	//   Address Space Identifier
#define	SATP_PPN		__BITS(43, 0)	//   Physical Page Number
#else
#define	SATP_MODE		__BIT(31)	// Translation mode
#define	 SATP_MODE_BARE		0		//   No translation or protection
#define	 SATP_MODE_SV32		1		//   Page-based 32-bit virt addr
#define	SATP_ASID		__BITS(30, 22)	//   Address Space Identifier
#define	SATP_PPN		__BITS(21, 0)	//   Physical Page Number
#endif

RISCVREG_READ_WRITE_INLINE(satp)

/* Fake "ASID" CSR (a field of SATP register) functions */
static inline uint32_t
csr_asid_read(void)
{
	uintptr_t satp = csr_satp_read();
	return __SHIFTOUT(satp, SATP_ASID);
}

static inline void
csr_asid_write(uint32_t asid)
{
	uintptr_t satp = csr_satp_read();
	satp &= ~SATP_ASID;
	satp |= __SHIFTIN(asid, SATP_ASID);
	csr_satp_write(satp);
}

#endif /* _RISCV_SYSREG_H_ */