Home | History | Annotate | Line # | Download | only in include
      1 /* $NetBSD: sysreg.h,v 1.34 2025/10/12 04:08:26 thorpej Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2014 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Matt Thomas of 3am Software Foundry.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #ifndef _RISCV_SYSREG_H_
     33 #define	_RISCV_SYSREG_H_
     34 
     35 #ifndef _KERNEL
     36 #include <sys/param.h>
     37 #endif
     38 
     39 #include <riscv/reg.h>
     40 
     41 /* CPU vendors (get CSR value from SBI). */
     42 #define CPU_VENDOR_SIFIVE		0x489
     43 #define  CPU_SIFIVE_ARCH_7SERIES	0x8000000000000007
     44 
     45 #define CPU_VENDOR_THEAD		0x5b7
     46 
     47 #define	FCSR_FMASK	0	// no exception bits
     48 #define	FCSR_FRM	__BITS(7, 5)
     49 #define	 FCSR_FRM_RNE	0b000	// Round Nearest, ties to Even
     50 #define	 FCSR_FRM_RTZ	0b001	// Round Towards Zero
     51 #define	 FCSR_FRM_RDN	0b010	// Round DowN (-infinity)
     52 #define	 FCSR_FRM_RUP	0b011	// Round UP (+infinity)
     53 #define	 FCSR_FRM_RMM	0b100	// Round to nearest, ties to Max Magnitude
     54 #define	 FCSR_FRM_DYN	0b111	// Dynamic rounding
     55 #define	FCSR_FFLAGS	__BITS(4, 0)	// Sticky bits
     56 #define	FCSR_NV		__BIT(4)	// iNValid operation
     57 #define	FCSR_DZ		__BIT(3)	// Divide by Zero
     58 #define	FCSR_OF		__BIT(2)	// OverFlow
     59 #define	FCSR_UF		__BIT(1)	// UnderFlow
     60 #define	FCSR_NX		__BIT(0)	// iNeXact
     61 
     62 static inline uint32_t
     63 fcsr_read(void)
     64 {
     65 	uint32_t __fcsr;
     66 	asm("frcsr %0" : "=r"(__fcsr) :: "memory");
     67 	return __fcsr;
     68 }
     69 
     70 static inline uint32_t
     71 fcsr_write(uint32_t __new)
     72 {
     73 	uint32_t __old;
     74 	asm volatile("fscsr %0, %1" : "=r"(__old) : "r"(__new) : "memory");
     75 	return __old;
     76 }
     77 
     78 static inline uint32_t
     79 fcsr_fflags_read(void)
     80 {
     81 	uint32_t __old;
     82 	asm("frflags %0" : "=r"(__old) :: "memory");
     83 	return __old;
     84 }
     85 
     86 static inline uint32_t
     87 fcsr_fflags_write(uint32_t __new)
     88 {
     89 	uint32_t __old;
     90 	asm volatile("fsflags %0, %1" : "=r"(__old) : "r"(__new) : "memory");
     91 	return __old;
     92 }
     93 
     94 static inline uint32_t
     95 fcsr_frm_read(void)
     96 {
     97 	uint32_t __old;
     98 	asm("frrm\t%0" : "=r"(__old) :: "memory");
     99 	return __old;
    100 }
    101 
    102 static inline uint32_t
    103 fcsr_frm_write(uint32_t __new)
    104 {
    105 	uint32_t __old;
    106 	asm volatile("fsrm\t%0, %1" : "=r"(__old) : "r"(__new) : "memory");
    107 	return __old;
    108 }
    109 
    110 #define	RISCVREG_READ_INLINE(regname)					\
    111 static inline uintptr_t							\
    112 csr_##regname##_read(void)						\
    113 {									\
    114 	uintptr_t __rv;							\
    115 	asm volatile("csrr %0, " #regname : "=r"(__rv) :: "memory");	\
    116 	return __rv;							\
    117 }
    118 
    119 #define	RISCVREG_WRITE_INLINE(regname)					\
    120 static inline void							\
    121 csr_##regname##_write(uintptr_t __val)					\
    122 {									\
    123 	asm volatile("csrw " #regname ", %0" :: "r"(__val) : "memory");	\
    124 }
    125 
    126 #define	RISCVREG_SET_INLINE(regname)					\
    127 static inline void							\
    128 csr_##regname##_set(uintptr_t __mask)					\
    129 {									\
    130 	if (__builtin_constant_p(__mask) && __mask < 0x20) {		\
    131 		asm volatile("csrsi " #regname ", %0" :: "i"(__mask) :	\
    132 		    "memory");						\
    133 	} else {							\
    134 		asm volatile("csrs " #regname ", %0" :: "r"(__mask) :	\
    135 		    "memory");						\
    136 	}								\
    137 }
    138 
    139 #define	RISCVREG_CLEAR_INLINE(regname)					\
    140 static inline void							\
    141 csr_##regname##_clear(uintptr_t __mask)					\
    142 {									\
    143 	if (__builtin_constant_p(__mask) && __mask < 0x20) {		\
    144 		asm volatile("csrci " #regname ", %0" :: "i"(__mask) :	\
    145 		    "memory");						\
    146 	} else {							\
    147 		asm volatile("csrc " #regname ", %0" :: "r"(__mask) :	\
    148 		    "memory");						\
    149 	}								\
    150 }
    151 
    152 #define	RISCVREG_READ_WRITE_INLINE(regname)				\
    153 RISCVREG_READ_INLINE(regname)						\
    154 RISCVREG_WRITE_INLINE(regname)
    155 #define	RISCVREG_SET_CLEAR_INLINE(regname)				\
    156 RISCVREG_SET_INLINE(regname)						\
    157 RISCVREG_CLEAR_INLINE(regname)
    158 #define	RISCVREG_READ_SET_CLEAR_INLINE(regname)				\
    159 RISCVREG_READ_INLINE(regname)						\
    160 RISCVREG_SET_CLEAR_INLINE(regname)
    161 #define	RISCVREG_READ_WRITE_SET_CLEAR_INLINE(regname)			\
    162 RISCVREG_READ_WRITE_INLINE(regname)					\
    163 RISCVREG_SET_CLEAR_INLINE(regname)
    164 
    165 /* Supervisor Status Register */
    166 RISCVREG_READ_SET_CLEAR_INLINE(sstatus)		// supervisor status register
    167 #ifdef _LP64
    168 #define	SR_WPRI		__BITS(62, 34) | __BITS(31, 20) | \
    169 			__BIT(17) | __BITS(12, 11) | __BIT(7) | __BITS(4, 2) | \
    170 			__BIT(0)
    171 #define	SR_SD		__BIT(63)	// any of FS or VS or XS dirty
    172 			/* Bits 62-34 are WPRI */
    173 #define	SR_UXL		__BITS(33, 32)	// U-mode XLEN
    174 #define	 SR_UXL_32	1		//   XLEN ==  32
    175 #define	 SR_UXL_64	2		//   XLEN ==  64
    176 #define	 SR_UXL_128	3		//   XLEN == 128
    177 			/* Bits 31-20 are WPRI*/
    178 #else
    179 #define	SR_WPRI		__BITS(30, 20) | \
    180 			__BIT(17) | __BITS(12, 11) | __BIT(7) | __BITS(4, 2) | \
    181 			__BIT(0)
    182 #define	SR_SD		__BIT(31)	// any of FS or VS or XS dirty
    183 			/* Bits 30-20 are WPRI*/
    184 #endif /* _LP64 */
    185 
    186 /* Both RV32 and RV64 have the bottom 20 bits shared */
    187 #define	SR_MXR		__BIT(19)	// Make eXecutable Readable
    188 #define	SR_SUM		__BIT(18)	// permit Supervisor User Memory access
    189 			/* Bit 17 is WPRI */
    190 #define	SR_XS		__BITS(16, 15)	// Vector extension state
    191 #define	 SR_XS_OFF		0	//   All off
    192 #define	 SR_XS_SOME_ON		1	//   None dirty or clean, some on
    193 #define	 SR_XS_SOME_CLEAN	2	//   None dirty, some clean
    194 #define	 SR_XS_SOME_DIRTY	3	//   Some dirty
    195 #define	SR_FS		__BITS(14, 13)	// Floating-point unit state
    196 #define	 SR_FS_OFF	0		//   Off
    197 #define	 SR_FS_INITIAL	1		//   Initial
    198 #define	 SR_FS_CLEAN	2		//   Clean
    199 #define	 SR_FS_DIRTY	3		//   Dirty
    200 			/* Bits 12-11 are WPRI */
    201 #define	SR_VS		__BITS(10, 9)	// User-mode extension state
    202 #define	 SR_VS_OFF	SR_FS_OFF	//   Off
    203 #define	 SR_VS_INITIAL	SR_FS_INITIAL	//   Initial
    204 #define	 SR_VS_CLEAN	SR_FS_CLEAN	//   Clean
    205 #define	 SR_VS_DIRTY	SR_FS_DIRTY	//   Dirty
    206 #define	SR_SPP		__BIT(8)	// Priv level before supervisor mode
    207 			/* Bit 7 is WPRI */
    208 #define	SR_UBE		__BIT(6)	// User-mode endianness
    209 #define	SR_SPIE		__BIT(5)	// S-Mode interrupts enabled before trap
    210 			/* Bits 4-2 are WPRI */
    211 #define	SR_SIE		__BIT(1)	// Supervisor mode interrupt enable
    212 			/* Bit 0 is WPRI */
    213 
    214 /* Supervisor interrupt registers */
    215 /* ... interrupt pending register (sip) */
    216 RISCVREG_READ_SET_CLEAR_INLINE(sip)		// supervisor interrupt pending
    217 			/* Bit (XLEN-1) - 10 is WIRI */
    218 #define	SIP_SEIP	__BIT(9)	// S-mode interrupt pending
    219 			/* Bit 8-6 is WIRI */
    220 #define	SIP_STIP	__BIT(5)	// S-mode timer interrupt pending
    221 			/* Bit 4-2 is WIRI */
    222 #define	SIP_SSIP	__BIT(1)	// S-mode software interrupt pending
    223 			/* Bit 0 is WIRI */
    224 
    225 /* ... interrupt-enable register (sie) */
    226 RISCVREG_READ_SET_CLEAR_INLINE(sie)		// supervisor interrupt enable
    227 			/* Bit (XLEN-1) - 10 is WIRI */
    228 #define	SIE_SEIE	__BIT(9)	// S-mode interrupt enable
    229 			/* Bit 8-6 is WIRI */
    230 #define	SIE_STIE	__BIT(5)	// S-mode timer interrupt enable
    231 			/* Bit 4-2 is WIRI */
    232 #define	SIE_SSIE	__BIT(1)	// S-mode software interrupt enable
    233 			/* Bit 0 is WIRI */
    234 
    235 // U-mode sstatus values
    236 #ifdef _LP64
    237 #define	SR_USER64	(SR_SPIE | __SHIFTIN(SR_UXL_64, SR_UXL))
    238 #define	SR_USER32	(SR_SPIE | __SHIFTIN(SR_UXL_32, SR_UXL))
    239 #else
    240 #define	SR_USER		(SR_SPIE)
    241 #endif
    242 
    243 // Cause register
    244 #define	CAUSE_INTERRUPT_P(cause)	((cause) & __BIT(XLEN - 1))
    245 #define	CAUSE_CODE(cause)		((cause) & __BITS(XLEN - 2, 0))
    246 
    247 // Cause register - exceptions
    248 #define	CAUSE_FETCH_MISALIGNED		0
    249 #define	CAUSE_FETCH_ACCESS		1
    250 #define	CAUSE_ILLEGAL_INSTRUCTION	2
    251 #define	CAUSE_BREAKPOINT		3
    252 #define	CAUSE_LOAD_MISALIGNED		4
    253 #define	CAUSE_LOAD_ACCESS		5
    254 #define	CAUSE_STORE_MISALIGNED		6
    255 #define	CAUSE_STORE_ACCESS		7
    256 #define	CAUSE_USER_ECALL		8
    257 #define	CAUSE_SYSCALL			CAUSE_USER_ECALL /* convenience alias */
    258 #define	CAUSE_SUPERVISOR_ECALL		9
    259 /* 10 is reserved */
    260 #define	CAUSE_MACHINE_ECALL		11
    261 #define	CAUSE_FETCH_PAGE_FAULT		12
    262 #define	CAUSE_LOAD_PAGE_FAULT		13
    263 /* 14 is Reserved */
    264 #define	CAUSE_STORE_PAGE_FAULT		15
    265 /* >= 16 is reserved/custom */
    266 
    267 // Cause register - interrupts
    268 #define	IRQ_SUPERVISOR_SOFTWARE		 1
    269 #define	IRQ_VIRTUAL_SUPERVISOR_SOFTWARE	 2
    270 #define	IRQ_MACHINE_SOFTWARE		 3
    271 #define	IRQ_SUPERVISOR_TIMER		 5
    272 #define	IRQ_VIRTUAL_SUPERVISOR_TIMER	 6
    273 #define	IRQ_MACHINE_TIMER		 7
    274 #define	IRQ_SUPERVISOR_EXTERNAL		 9
    275 #define	IRQ_VIRTUAL_SUPERVISOR_EXTERNAL	10
    276 #define	IRQ_MACHINE_EXTERNAL		11
    277 #define	IRQ_SUPERVISOR_GUEST_EXTERNAL	12
    278 #define IRQ_NSOURCES			16
    279 
    280 RISCVREG_READ_INLINE(time)
    281 #ifdef _LP64
    282 RISCVREG_READ_INLINE(cycle)
    283 #else /* !_LP64 */
    284 static inline uint64_t
    285 csr_cycle_read(void)
    286 {
    287 	uint32_t __hi0, __hi1, __lo0;
    288 	do {
    289 		asm volatile(
    290 			"csrr\t%[__hi0], cycleh"
    291 		"\n\t"	"csrr\t%[__lo0], cycle"
    292 		"\n\t"	"csrr\t%[__hi1], cycleh"
    293 		   :	[__hi0] "=r"(__hi0),
    294 			[__lo0] "=r"(__lo0),
    295 			[__hi1] "=r"(__hi1));
    296 	} while (__hi0 != __hi1);
    297 	return
    298 	    __SHIFTIN(__hi0, __BITS(63, 32)) |
    299 	    __SHIFTIN(__lo0, __BITS(31,  0));
    300 }
    301 #endif /* !_LP64 */
    302 
    303 #ifdef _LP64
    304 #define	SATP_MODE		__BITS(63, 60)	// Translation mode
    305 #define	 SATP_MODE_BARE		0		//   No translation or protection
    306 				/* modes 1-7 reserved for standard use */
    307 #define	 SATP_MODE_SV39		8		//   Page-based 39-bit virt addr
    308 #define	 SATP_MODE_SV48		9		//   Page-based 48-bit virt addr
    309 #define	 SATP_MODE_SV57		10		//   Page-based 57-bit virt addr
    310 #define	 SATP_MODE_SV64		11		//   Page-based 64-bit virt addr
    311 				/* modes 12-13 reserved for standard use */
    312 				/* modes 14-15 designated for custom use */
    313 #define	SATP_ASID		__BITS(59, 44)	//   Address Space Identifier
    314 #define	SATP_PPN		__BITS(43, 0)	//   Physical Page Number
    315 #else
    316 #define	SATP_MODE		__BIT(31)	// Translation mode
    317 #define	 SATP_MODE_BARE		0		//   No translation or protection
    318 #define	 SATP_MODE_SV32		1		//   Page-based 32-bit virt addr
    319 #define	SATP_ASID		__BITS(30, 22)	//   Address Space Identifier
    320 #define	SATP_PPN		__BITS(21, 0)	//   Physical Page Number
    321 #endif
    322 
    323 RISCVREG_READ_WRITE_INLINE(satp)
    324 
    325 /* Fake "ASID" CSR (a field of SATP register) functions */
    326 static inline uint32_t
    327 csr_asid_read(void)
    328 {
    329 	uintptr_t satp = csr_satp_read();
    330 	return __SHIFTOUT(satp, SATP_ASID);
    331 }
    332 
    333 static inline void
    334 csr_asid_write(uint32_t asid)
    335 {
    336 	uintptr_t satp = csr_satp_read();
    337 	satp &= ~SATP_ASID;
    338 	satp |= __SHIFTIN(asid, SATP_ASID);
    339 	csr_satp_write(satp);
    340 }
    341 
    342 /* Non-standard CSRs. */
    343 static inline uintptr_t
    344 csr_thead_sxstatus_read(void)
    345 {
    346 	uintptr_t __rv;
    347 	asm volatile("csrr %0, 0x5c0" : "=r"(__rv) :: "memory");
    348 	return __rv;
    349 }
    350 
    351 #define	TX_SXSTATUS_MAEE	__BIT(21)
    352 #define	TH_SXSTATUS_THEADISAEE	__BIT(22)
    353 
    354 #endif /* _RISCV_SYSREG_H_ */
    355