1 // Copyright (c) 2013, The Regents of the University of California (Regents).
2 // Copyright (c) 2018-2019, The libfemto authors
3 // Copyright (c) 2020 Espressif Systems (Shanghai) PTE LTD
4 // All Rights Reserved.
5 
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // 1. Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in the
12 //    documentation and/or other materials provided with the distribution.
13 // 3. Neither the name of the Regents nor the
14 //    names of its contributors may be used to endorse or promote products
15 //    derived from this software without specific prior written permission.
16 
17 // IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
18 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
19 // OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
20 // BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21 
22 // REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 // PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
25 // HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
26 // MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
27 
28 #pragma once
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
34 #include <stdint.h>
35 #include <stddef.h>
36 #include <stdbool.h>
37 #include <sys/param.h>
38 #include "encoding.h"
39 #include "esp_assert.h"
40 
41 /********************************************************
42  Physical Memory Attributes (PMA) register fields
43  (privileged spec)
44  ********************************************************/
45 
46 /********************************************************
47    PMA CSR and TOR & NAPOT macros
48  ********************************************************/
49 #define CSR_PMACFG0  0xBC0
50 #define CSR_PMAADDR0 0xBD0
51 
52 #define CSR_PMACFG(i)  (CSR_PMACFG0 + (i))
53 #define CSR_PMAADDR(i)  (CSR_PMAADDR0 + (i))
54 
55 #define PMA_EN    BIT(0)
56 #define PMA_R     BIT(4)
57 #define PMA_W     BIT(3)
58 #define PMA_X     BIT(2)
59 #define PMA_L     BIT(29)
60 #define PMA_SHIFT 2
61 
62 #define PMA_TOR   0x40000000
63 #define PMA_NA4   0x80000000
64 #define PMA_NAPOT 0xC0000000
65 
66 #define PMA_NONCACHEABLE     BIT(27)
67 #define PMA_WRITETHROUGH     BIT(26)
68 #define PMA_WRITEMISSNOALLOC BIT(25)
69 #define PMA_READMISSNOALLOC  BIT(24)
70 
71 #define PMA_ENTRY_SET_TOR(ENTRY, ADDR, CFG)                            \
72     do {                                                               \
73         RV_WRITE_CSR((CSR_PMAADDR0) + (ENTRY), (ADDR) >> (PMA_SHIFT)); \
74         RV_WRITE_CSR((CSR_PMACFG0) + (ENTRY), CFG);                    \
75     } while (0)
76 
77 #define PMA_ENTRY_SET_NAPOT(ENTRY, ADDR, SIZE, CFG)                                \
78     do {                                                                           \
79         ESP_STATIC_ASSERT(__builtin_popcount((SIZE)) == 1, "Size must be a power of 2"); \
80         ESP_STATIC_ASSERT((ADDR) % ((SIZE)) == 0, "Addr must be aligned to size"); \
81         RV_WRITE_CSR((CSR_PMAADDR0) + (ENTRY), ((ADDR) | ((SIZE >> 1) - 1)) >> 2); \
82         RV_WRITE_CSR((CSR_PMACFG0) + (ENTRY), CFG);                                \
83     } while (0)
84 
85 /********************************************************
86  Physical Memory Protection (PMP) register fields
87  (privileged spec)
88  ********************************************************/
89 
90 /* Value of pmpcfg0 CSR. Note this macro is only needed for calculations like (CSR_PMPCFG0 + 1), which must
91    still be constant at compile time. Use the assembler name pmpcfg0, pmpcfg1, pmpcfg2, etc. in other cases */
92 #define CSR_PMPCFG0 0x3A0
93 
94 /* Value of pmpaddr0 CSR. Note, as above, this macro is only needed for calculations and the assembler names
95    pmpaddr0, pmpaddr1, pmpaddr2, etc should be used otherwise. */
96 #define CSR_PMPADDR0 0x3B0
97 
98 /* Generate the PMP address field value when PMPCFG.A == NAPOT
99 
100    START & END should be calculated at compile time. The size of the region
101    (END-START) must be a power of 2 size, and START must be aligned to this
102    size.
103 
104    Note: this value must be right-shifted PMP_SHIFT when written to the PMPADDR
105    register. The PMP_ENTRY_SET macro will do this.
106  */
107 #define PMPADDR_NAPOT(START, END) ({                                    \
108             ESP_STATIC_ASSERT(__builtin_popcount((END)-(START)) == 1, "Size must be a power of 2"); \
109             ESP_STATIC_ASSERT((START) % ((END)-(START)) == 0, "Start must be aligned to size"); \
110             (((START)) | (((END)-(START)-1)>>1));                       \
111         })
112 
113 #define PMPADDR_ALL 0xFFFFFFFF
114 
115 
116 /* Set a PMP entry.
117 
118    - ENTRY is number of the PMP entry to set. This must be a compile-time constant because it's used to
119      generate specific assembly instructions.
120    - ADDR is the address to write to the PMPADDRx register. Note this is the unshifted address.
121    - CFG is the configuration value to write to the correct CFG entry register. Note that
122      the macro only sets bits in the CFG register, so it sould be zeroed already.
123 */
124 #define PMP_ENTRY_SET(ENTRY, ADDR, CFG) do {  \
125     RV_WRITE_CSR((CSR_PMPADDR0) + (ENTRY), (ADDR) >> (PMP_SHIFT));    \
126     RV_SET_CSR((CSR_PMPCFG0) + (ENTRY)/4, ((CFG)&0xFF) << (ENTRY%4)*8); \
127     } while(0)
128 
129 /*Only set PMPCFG entries*/
130 #define PMP_ENTRY_CFG_SET(ENTRY, CFG) do {\
131     RV_SET_CSR((CSR_PMPCFG0) + (ENTRY)/4, ((CFG)&0xFF) << (ENTRY%4)*8); \
132     } while(0)
133 
134 /*Reset all permissions of a particular PMPCFG entry*/
135 #define PMP_ENTRY_CFG_RESET(ENTRY) do {\
136     RV_CLEAR_CSR((CSR_PMPCFG0) + (ENTRY)/4, (0xFF) << (ENTRY%4)*8); \
137     } while(0)
138 
139 /********************************************************
140    Trigger Module register fields (Debug specification)
141  ********************************************************/
142 
143 #define TCONTROL_MTE     (1<<3)    /*R/W, Current M mode trigger enable bit*/
144 #define TCONTROL_MPTE    (1<<7)    /*R/W, Previous M mode trigger enable bit*/
145 
146 #define TDATA1_LOAD      (1<<0)  /*R/W,Fire trigger on load address match*/
147 #define TDATA1_STORE     (1<<1)  /*R/W,Fire trigger on store address mat*/
148 #define TDATA1_EXECUTE   (1<<2)  /*R/W,Fire trigger on instruction fetch address match*/
149 #define TDATA1_USER      (1<<3)  /*R/W,allow trigger to be fired in user mode*/
150 #define TDATA1_MACHINE   (1<<6)  /*R/W,Allow trigger to be fired while hart is executing in machine mode*/
151 #define TDATA1_MATCH_EXACT  (0)
152 #define TDATA1_MATCH_NAPOT  (1<<7)
153 #define TDATA1_MATCH_V   (0xF)   /*R/W,Address match type :0 : Exact byte match  1 : NAPOT range match */
154 #define TDATA1_MATCH_S   (7)
155 #define TDATA1_HIT_S     (20)
156 
157 
158 /* RISC-V CSR macros
159  * Adapted from https://github.com/michaeljclark/riscv-probe/blob/master/libfemto/include/arch/riscv/machine.h
160  */
161 
162 #define RV_READ_CONST_CSR(reg) ({ unsigned long __tmp; \
163   asm ("csrr %0, " _CSR_STRINGIFY(reg) : "=r"(__tmp)); __tmp; })
164 
165 #define RV_READ_CSR(reg) ({ unsigned long __tmp; \
166   asm volatile ("csrr %0, " _CSR_STRINGIFY(reg) : "=r"(__tmp)); __tmp; })
167 
168 #define RV_WRITE_CSR(reg, val) ({ \
169   asm volatile ("csrw " _CSR_STRINGIFY(reg) ", %0" :: "rK"(val)); })
170 
171 #define RV_SWAP_CSR(reg, val) ({ unsigned long __tmp; \
172   asm volatile ("csrrw %0, " _CSR_STRINGIFY(reg) ", %1" : "=r"(__tmp) : "rK"(val)); __tmp; })
173 
174 /* Note: this uses the atomic read-and-set instruction so possible to read the old CSR value as a result */
175 #define RV_SET_CSR(reg, bit) ({ unsigned long __tmp; \
176   asm volatile ("csrrs %0, " _CSR_STRINGIFY(reg) ", %1" : "=r"(__tmp) : "rK"(bit)); __tmp; })
177 
178 /* Note: this uses the atomic read-and-clear instruction so possible to read the old CSR value as a result */
179 #define RV_CLEAR_CSR(reg, bit) ({ unsigned long __tmp; \
180   asm volatile ("csrrc %0, " _CSR_STRINGIFY(reg) ", %1" : "=r"(__tmp) : "rK"(bit)); __tmp; })
181 
182 #define RV_SET_CSR_FIELD(_r, _f, _v) ({ (RV_WRITE_CSR((_r),((RV_READ_CSR(_r) & ~((_f##_V) << (_f##_S)))|(((_v) & (_f##_V))<<(_f##_S)))));})
183 #define RV_CLEAR_CSR_FIELD(_r, _f) ({ (RV_WRITE_CSR((_r),(RV_READ_CSR(_r) & ~((_f##_V) << (_f##_S)))));})
184 
185 #define _CSR_STRINGIFY(REG) #REG /* needed so the 'reg' argument can be a macro or a register name */
186 
187 #ifdef __cplusplus
188 }
189 #endif
190