1 /*
2 * Copyright (c) 2019 Nuclei Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 #ifndef __CORE_FEATURE_PMP_H__
19 #define __CORE_FEATURE_PMP_H__
20 /*!
21 * @file core_feature_pmp.h
22 * @brief PMP feature API header file for Nuclei N/NX Core
23 */
24 /*
25 * PMP Feature Configuration Macro:
26 * 1. __PMP_PRESENT: Define whether Physical Memory Protection(PMP) is present or not
27 * * 0: Not present
28 * * 1: Present
29 * 2. __PMP_ENTRY_NUM: Define the number of PMP entries, only 8 or 16 is configurable.
30 */
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 #if defined(__PMP_PRESENT) && (__PMP_PRESENT == 1)
36 /* ===== PMP Operations ===== */
37 /**
38 * \defgroup NMSIS_Core_PMP_Functions PMP Functions
39 * \ingroup NMSIS_Core
40 * \brief Functions that related to the RISCV Phyiscal Memory Protection.
41 * \details
42 * Optional physical memory protection (PMP) unit provides per-hart machine-mode
43 * control registers to allow physical memory access privileges (read, write, execute)
44 * to be specified for each physical memory region.
45 *
46 * The PMP can supports region access control settings as small as four bytes.
47 *
48 * @{
49 */
50 #ifndef __PMP_ENTRY_NUM
51 /* numbers of PMP entries(__PMP_ENTRY_NUM) should be defined in <Device.h> */
52 #error "__PMP_ENTRY_NUM is not defined, please check!"
53 #endif
54
55 /**
56 * \brief Get 8bit PMPxCFG Register by PMP entry index
57 * \details Return the content of the PMPxCFG Register.
58 * \param [in] idx PMP region index(0-15)
59 * \return PMPxCFG Register value
60 */
__get_PMPxCFG(uint32_t idx)61 __STATIC_INLINE uint8_t __get_PMPxCFG(uint32_t idx)
62 {
63 rv_csr_t pmpcfg = 0;
64
65 if (idx >= __PMP_ENTRY_NUM) return 0;
66 #if __RISCV_XLEN == 32
67 if (idx < 4) {
68 pmpcfg = __RV_CSR_READ(CSR_PMPCFG0);
69 } else if ((idx >=4) && (idx < 8)) {
70 idx -= 4;
71 pmpcfg = __RV_CSR_READ(CSR_PMPCFG1);
72 } else if ((idx >=8) && (idx < 12)) {
73 idx -= 8;
74 pmpcfg = __RV_CSR_READ(CSR_PMPCFG2);
75 } else {
76 idx -= 12;
77 pmpcfg = __RV_CSR_READ(CSR_PMPCFG3);
78 }
79
80 idx = idx << 3;
81 return (uint8_t)((pmpcfg>>idx) & 0xFF);
82 #elif __RISCV_XLEN == 64
83 if (idx < 8) {
84 pmpcfg = __RV_CSR_READ(CSR_PMPCFG0);
85 } else {
86 idx -= 8;
87 pmpcfg = __RV_CSR_READ(CSR_PMPCFG2);
88 }
89 idx = idx << 3;
90 return (uint8_t)((pmpcfg>>idx) & 0xFF);
91 #else
92 // TODO Add RV128 Handling
93 return 0;
94 #endif
95 }
96
97 /**
98 * \brief Set 8bit PMPxCFG by pmp entry index
99 * \details Set the given pmpxcfg value to the PMPxCFG Register.
100 * \param [in] idx PMPx region index(0-15)
101 * \param [in] pmpxcfg PMPxCFG register value to set
102 */
__set_PMPxCFG(uint32_t idx,uint8_t pmpxcfg)103 __STATIC_INLINE void __set_PMPxCFG(uint32_t idx, uint8_t pmpxcfg)
104 {
105 rv_csr_t pmpcfgx = 0;
106 if (idx >= __PMP_ENTRY_NUM) return;
107
108 #if __RISCV_XLEN == 32
109 if (idx < 4) {
110 pmpcfgx = __RV_CSR_READ(CSR_PMPCFG0);
111 idx = idx << 3;
112 pmpcfgx = (pmpcfgx & ~(0xFFUL << idx)) | ((rv_csr_t)pmpxcfg << idx);
113 __RV_CSR_WRITE(CSR_PMPCFG0, pmpcfgx);
114 } else if ((idx >=4) && (idx < 8)) {
115 idx -= 4;
116 pmpcfgx = __RV_CSR_READ(CSR_PMPCFG1);
117 idx = idx << 3;
118 pmpcfgx = (pmpcfgx & ~(0xFFUL << idx)) | ((rv_csr_t)pmpxcfg << idx);
119 __RV_CSR_WRITE(CSR_PMPCFG1, pmpcfgx);
120 } else if ((idx >=8) && (idx < 12)) {
121 idx -= 8;
122 pmpcfgx = __RV_CSR_READ(CSR_PMPCFG2);
123 idx = idx << 3;
124 pmpcfgx = (pmpcfgx & ~(0xFFUL << idx)) | ((rv_csr_t)pmpxcfg << idx);
125 __RV_CSR_WRITE(CSR_PMPCFG2, pmpcfgx);
126 } else {
127 idx -= 12;
128 pmpcfgx = __RV_CSR_READ(CSR_PMPCFG3);
129 idx = idx << 3;
130 pmpcfgx = (pmpcfgx & ~(0xFFUL << idx)) | ((rv_csr_t)pmpxcfg << idx);
131 __RV_CSR_WRITE(CSR_PMPCFG3, pmpcfgx);
132 }
133 #elif __RISCV_XLEN == 64
134 if (idx < 8) {
135 pmpcfgx = __RV_CSR_READ(CSR_PMPCFG0);
136 idx = idx << 3;
137 pmpcfgx = (pmpcfgx & ~(0xFFULL << idx)) | ((rv_csr_t)pmpxcfg << idx);
138 __RV_CSR_WRITE(CSR_PMPCFG0, pmpcfgx);
139 } else {
140 idx -= 8;
141 pmpcfgx = __RV_CSR_READ(CSR_PMPCFG2);
142 idx = idx << 3;
143 pmpcfgx = (pmpcfgx & ~(0xFFULL << idx)) | ((rv_csr_t)pmpxcfg << idx);
144 __RV_CSR_WRITE(CSR_PMPCFG2, pmpcfgx);
145 }
146 #else
147 // TODO Add RV128 Handling
148 #endif
149 }
150
151 /**
152 * \brief Get PMPCFGx Register by index
153 * \details Return the content of the PMPCFGx Register.
154 * \param [in] idx PMPCFG CSR index(0-3)
155 * \return PMPCFGx Register value
156 * \remark
157 * - For RV64, only idx = 0 and idx = 2 is allowed.
158 * pmpcfg0 and pmpcfg2 hold the configurations
159 * for the 16 PMP entries, pmpcfg1 and pmpcfg3 are illegal
160 * - For RV32, pmpcfg0–pmpcfg3, hold the configurations
161 * pmp0cfg–pmp15cfg for the 16 PMP entries
162 */
__get_PMPCFGx(uint32_t idx)163 __STATIC_INLINE rv_csr_t __get_PMPCFGx(uint32_t idx)
164 {
165 switch (idx) {
166 case 0: return __RV_CSR_READ(CSR_PMPCFG0);
167 case 1: return __RV_CSR_READ(CSR_PMPCFG1);
168 case 2: return __RV_CSR_READ(CSR_PMPCFG2);
169 case 3: return __RV_CSR_READ(CSR_PMPCFG3);
170 default: return 0;
171 }
172 }
173
174 /**
175 * \brief Set PMPCFGx by index
176 * \details Write the given value to the PMPCFGx Register.
177 * \param [in] idx PMPCFG CSR index(0-3)
178 * \param [in] pmpcfg PMPCFGx Register value to set
179 * \remark
180 * - For RV64, only idx = 0 and idx = 2 is allowed.
181 * pmpcfg0 and pmpcfg2 hold the configurations
182 * for the 16 PMP entries, pmpcfg1 and pmpcfg3 are illegal
183 * - For RV32, pmpcfg0–pmpcfg3, hold the configurations
184 * pmp0cfg–pmp15cfg for the 16 PMP entries
185 */
__set_PMPCFGx(uint32_t idx,rv_csr_t pmpcfg)186 __STATIC_INLINE void __set_PMPCFGx(uint32_t idx, rv_csr_t pmpcfg)
187 {
188 switch (idx) {
189 case 0: __RV_CSR_WRITE(CSR_PMPCFG0, pmpcfg); break;
190 case 1: __RV_CSR_WRITE(CSR_PMPCFG1, pmpcfg); break;
191 case 2: __RV_CSR_WRITE(CSR_PMPCFG2, pmpcfg); break;
192 case 3: __RV_CSR_WRITE(CSR_PMPCFG3, pmpcfg); break;
193 default: return;
194 }
195 }
196
197 /**
198 * \brief Get PMPADDRx Register by index
199 * \details Return the content of the PMPADDRx Register.
200 * \param [in] idx PMP region index(0-15)
201 * \return PMPADDRx Register value
202 */
__get_PMPADDRx(uint32_t idx)203 __STATIC_INLINE rv_csr_t __get_PMPADDRx(uint32_t idx)
204 {
205 switch (idx) {
206 case 0: return __RV_CSR_READ(CSR_PMPADDR0);
207 case 1: return __RV_CSR_READ(CSR_PMPADDR1);
208 case 2: return __RV_CSR_READ(CSR_PMPADDR2);
209 case 3: return __RV_CSR_READ(CSR_PMPADDR3);
210 case 4: return __RV_CSR_READ(CSR_PMPADDR4);
211 case 5: return __RV_CSR_READ(CSR_PMPADDR5);
212 case 6: return __RV_CSR_READ(CSR_PMPADDR6);
213 case 7: return __RV_CSR_READ(CSR_PMPADDR7);
214 case 8: return __RV_CSR_READ(CSR_PMPADDR8);
215 case 9: return __RV_CSR_READ(CSR_PMPADDR9);
216 case 10: return __RV_CSR_READ(CSR_PMPADDR10);
217 case 11: return __RV_CSR_READ(CSR_PMPADDR11);
218 case 12: return __RV_CSR_READ(CSR_PMPADDR12);
219 case 13: return __RV_CSR_READ(CSR_PMPADDR13);
220 case 14: return __RV_CSR_READ(CSR_PMPADDR14);
221 case 15: return __RV_CSR_READ(CSR_PMPADDR15);
222 default: return 0;
223 }
224 }
225
226 /**
227 * \brief Set PMPADDRx by index
228 * \details Write the given value to the PMPADDRx Register.
229 * \param [in] idx PMP region index(0-15)
230 * \param [in] pmpaddr PMPADDRx Register value to set
231 */
__set_PMPADDRx(uint32_t idx,rv_csr_t pmpaddr)232 __STATIC_INLINE void __set_PMPADDRx(uint32_t idx, rv_csr_t pmpaddr)
233 {
234 switch (idx) {
235 case 0: __RV_CSR_WRITE(CSR_PMPADDR0, pmpaddr); break;
236 case 1: __RV_CSR_WRITE(CSR_PMPADDR1, pmpaddr); break;
237 case 2: __RV_CSR_WRITE(CSR_PMPADDR2, pmpaddr); break;
238 case 3: __RV_CSR_WRITE(CSR_PMPADDR3, pmpaddr); break;
239 case 4: __RV_CSR_WRITE(CSR_PMPADDR4, pmpaddr); break;
240 case 5: __RV_CSR_WRITE(CSR_PMPADDR5, pmpaddr); break;
241 case 6: __RV_CSR_WRITE(CSR_PMPADDR6, pmpaddr); break;
242 case 7: __RV_CSR_WRITE(CSR_PMPADDR7, pmpaddr); break;
243 case 8: __RV_CSR_WRITE(CSR_PMPADDR8, pmpaddr); break;
244 case 9: __RV_CSR_WRITE(CSR_PMPADDR9, pmpaddr); break;
245 case 10: __RV_CSR_WRITE(CSR_PMPADDR10, pmpaddr); break;
246 case 11: __RV_CSR_WRITE(CSR_PMPADDR11, pmpaddr); break;
247 case 12: __RV_CSR_WRITE(CSR_PMPADDR12, pmpaddr); break;
248 case 13: __RV_CSR_WRITE(CSR_PMPADDR13, pmpaddr); break;
249 case 14: __RV_CSR_WRITE(CSR_PMPADDR14, pmpaddr); break;
250 case 15: __RV_CSR_WRITE(CSR_PMPADDR15, pmpaddr); break;
251 default: return;
252 }
253 }
254 /** @} */ /* End of Doxygen Group NMSIS_Core_PMP_Functions */
255 #endif /* defined(__PMP_PRESENT) && (__PMP_PRESENT == 1) */
256
257 #ifdef __cplusplus
258 }
259 #endif
260 #endif /** __CORE_FEATURE_PMP_H__ */
261