Line data Source code
1 : // SPDX-License-Identifier: Apache-2.0
2 : // Copyright lowRISC contributors.
3 : // Copyright 2023 Antmicro, Ltd. <www.antmicro.com>
4 : //
5 : // Licensed under the Apache License, Version 2.0 (the "License");
6 : // you may not use this file except in compliance with the License.
7 : // You may obtain a copy of the License at
8 : //
9 : // http://www.apache.org/licenses/LICENSE-2.0
10 : //
11 : // Unless required by applicable law or agreed to in writing, software
12 : // distributed under the License is distributed on an "AS IS" BASIS,
13 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : // See the License for the specific language governing permissions and
15 : // limitations under the License.
16 :
17 : module el2_pmp
18 : import el2_pkg::*;
19 : #(
20 : parameter PMP_CHANNELS = 3,
21 : // Granularity of NAPOT access,
22 : // 0 = No restriction, 1 = 8 byte, 2 = 16 byte, 3 = 32 byte, etc.
23 : parameter PMP_GRANULARITY = 0, // TODO: Move to veer.config
24 : `include "el2_param.vh"
25 : ) (
26 77894486 : input logic clk, // Top level clock
27 340 : input logic rst_l, // Reset
28 : /* verilator coverage_off */
29 : input logic scan_mode, // Scan mode
30 : /* verilator coverage_on */
31 :
32 : `ifdef RV_SMEPMP
33 2 : input el2_mseccfg_pkt_t mseccfg, // mseccfg CSR content, RLB, MMWP and MML bits
34 : `endif
35 :
36 : `ifdef RV_USER_MODE
37 864 : input logic priv_mode_ns, // operating privilege mode (next clock cycle)
38 960 : input logic priv_mode_eff, // operating effective privilege mode
39 : `endif
40 :
41 0 : input el2_pmp_cfg_pkt_t pmp_pmpcfg [pt.PMP_ENTRIES],
42 0 : input logic [31:0] pmp_pmpaddr[pt.PMP_ENTRIES],
43 :
44 593781 : input logic [31:0] pmp_chan_addr[PMP_CHANNELS],
45 769 : input el2_pmp_type_pkt_t pmp_chan_type[PMP_CHANNELS],
46 137444 : output logic pmp_chan_err [PMP_CHANNELS]
47 : );
48 :
49 0 : logic [ 33:0] csr_pmp_addr_i [pt.PMP_ENTRIES];
50 789084 : logic [ 33:0] pmp_req_addr_i [ PMP_CHANNELS];
51 :
52 0 : logic [ 33:0] region_start_addr [pt.PMP_ENTRIES];
53 0 : logic [33:PMP_GRANULARITY+2] region_addr_mask [pt.PMP_ENTRIES];
54 583 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_gt;
55 1 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_lt;
56 921 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_eq;
57 2 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_all;
58 0 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_basic_perm_check;
59 350 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_perm_check;
60 :
61 : `ifdef RV_USER_MODE
62 76 : logic any_region_enabled;
63 : `endif
64 :
65 : ///////////////////////
66 : // Functions for PMP //
67 : ///////////////////////
68 :
69 : // Flow of the PMP checking operation follows as below
70 : //
71 : // basic_perm_check ---> perm_check_wrapper ---> orig_perm_check ---/
72 : // |
73 : // region_match_all -----------------> access_fault_check <----------
74 : // |
75 : // \--> pmp_chan_err
76 :
77 : // A wrapper function in which it is decided which form of permission check function gets called
78 16416 : function automatic logic perm_check_wrapper(el2_mseccfg_pkt_t csr_pmp_mseccfg,
79 : el2_pmp_cfg_pkt_t csr_pmp_cfg,
80 : el2_pmp_type_pkt_t req_type,
81 : logic priv_mode,
82 : logic permission_check);
83 :
84 16416 : return csr_pmp_mseccfg.MML ? mml_perm_check(csr_pmp_cfg,
85 16416 : req_type,
86 16416 : priv_mode,
87 16416 : permission_check) :
88 16416 : orig_perm_check(csr_pmp_cfg.lock,
89 16416 : priv_mode,
90 16416 : permission_check);
91 : endfunction
92 :
93 : // Compute permissions checks that apply when MSECCFG.MML is set. Added for Smepmp support.
94 1691520 : function automatic logic mml_perm_check(el2_pmp_cfg_pkt_t csr_pmp_cfg,
95 : el2_pmp_type_pkt_t pmp_req_type,
96 : logic priv_mode,
97 : logic permission_check);
98 : logic result;
99 1691520 : logic unused_cfg = |csr_pmp_cfg.mode;
100 :
101 211440 : if (!csr_pmp_cfg.read && csr_pmp_cfg.write) begin
102 : // Special-case shared regions where R = 0, W = 1
103 211440 : unique case ({csr_pmp_cfg.lock, csr_pmp_cfg.execute})
104 : // Read/write in M, read only in U
105 105720 : 2'b00: result =
106 105720 : (pmp_req_type == READ) |
107 105720 : ((pmp_req_type == WRITE) & ~priv_mode);
108 : // Read/write in M/U
109 0 : 2'b01: result =
110 0 : (pmp_req_type == READ) |
111 0 : (pmp_req_type == WRITE);
112 : // Execute only on M/U
113 0 : 2'b10: result = (pmp_req_type == EXEC);
114 : // Read/execute in M, execute only on U
115 105720 : 2'b11: result =
116 105720 : (pmp_req_type == EXEC) |
117 105720 : ((pmp_req_type == READ) & ~priv_mode);
118 : /* verilator coverage_off */
119 : default: ;
120 : /* verilator coverage_on */
121 : endcase
122 1480080 : end else begin
123 1480080 : if (csr_pmp_cfg.read & csr_pmp_cfg.write & csr_pmp_cfg.execute & csr_pmp_cfg.lock) begin
124 : // Special-case shared read only region when R = 1, W = 1, X = 1, L = 1
125 0 : result = (pmp_req_type == READ);
126 1480080 : end else begin
127 : // Otherwise use basic permission check. Permission is always denied if in U mode and
128 : // L is set or if in M mode and L is unset.
129 1480080 : result = permission_check & (priv_mode ? ~csr_pmp_cfg.lock : csr_pmp_cfg.lock);
130 : end
131 : end
132 1691520 : return result;
133 : endfunction
134 :
135 : // Compute permissions checks that apply when MSECCFG.MML is unset. This is the original PMP
136 : // behaviour before Smepmp was added.
137 2842507200 : function automatic logic orig_perm_check(logic pmp_cfg_lock,
138 : logic priv_mode,
139 : logic permission_check);
140 : // For M-mode, any region which matches with the L-bit clear, or with sufficient
141 : // access permissions will be allowed.
142 : // For other modes, the lock bit doesn't matter
143 2842507200 : return priv_mode ? (permission_check) : (~pmp_cfg_lock | permission_check);
144 : endfunction
145 :
146 : // Access fault determination / prioritization
147 1032 : function automatic logic access_fault_check(el2_mseccfg_pkt_t csr_pmp_mseccfg,
148 : el2_pmp_type_pkt_t req_type,
149 : logic [pt.PMP_ENTRIES-1:0] match_all,
150 : logic any_region_enabled,
151 : logic priv_mode,
152 : logic [pt.PMP_ENTRIES-1:0] final_perm_check);
153 :
154 : `ifdef RV_USER_MODE
155 : `ifdef RV_SMEPMP
156 : // When MSECCFG.MMWP is set default deny always, otherwise allow for M-mode, deny for other
157 : // modes. Also deny unmatched for M-mode when MSECCFG.MML is set and request type is EXEC.
158 261 : logic access_fail = csr_pmp_mseccfg.MMWP | priv_mode |
159 261 : (csr_pmp_mseccfg.MML && (req_type == EXEC));
160 : `else
161 : // When in user mode and at least one PMP region is enabled deny access by default.
162 : logic access_fail = any_region_enabled & priv_mode;
163 : `endif
164 : `else
165 771 : logic access_fail = 1'b0;
166 : `endif
167 :
168 1032 : logic matched = 1'b0;
169 :
170 : // PMP entries are statically prioritized, from 0 to N-1
171 : // The lowest-numbered PMP entry which matches an address determines accessibility
172 : /* verilator lint_off UNSIGNED */
173 1026 : for (int r = 0; r < pt.PMP_ENTRIES; r++) begin
174 1381262096 : if (!matched && match_all[r]) begin
175 85286720 : access_fail = ~final_perm_check[r];
176 85286720 : matched = 1'b1;
177 : end
178 : end
179 : /* verilator lint_on UNSIGNED */
180 1032 : return access_fail;
181 : endfunction
182 :
183 : // ---------------
184 : // Access checking
185 : // ---------------
186 :
187 : `ifdef RV_USER_MODE
188 0 : logic [pt.PMP_ENTRIES-1:0] region_enabled;
189 : for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_reg_ena
190 : assign region_enabled[r] = pmp_pmpcfg[r].mode != OFF;
191 : end
192 : assign any_region_enabled = |region_enabled;
193 : `endif
194 :
195 : for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_addr_exp
196 : assign csr_pmp_addr_i[r] = {
197 : pmp_pmpaddr[r], 2'b00
198 : }; // addr conv.: word @ 32-bit -> byte @ 34-bit
199 : // Start address for TOR matching
200 : if (r == 0) begin : g_entry0
201 : assign region_start_addr[r] = (pmp_pmpcfg[r].mode == TOR) ? 34'h000000000 : csr_pmp_addr_i[r];
202 : end else begin : g_oth
203 : assign region_start_addr[r] = (pmp_pmpcfg[r].mode == TOR) ? csr_pmp_addr_i[r-1] :
204 : csr_pmp_addr_i[r];
205 : end
206 : // Address mask for NA matching
207 : for (genvar b = PMP_GRANULARITY + 2; b < 34; b++) begin : g_bitmask
208 : if (b == 2) begin : g_bit0
209 : // Always mask bit 2 for NAPOT
210 : assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT);
211 : end else begin : g_others
212 : // We will mask this bit if it is within the programmed granule
213 : // i.e. addr = yyyy 0111
214 : // ^
215 : // | This bit pos is the top of the mask, all lower bits set
216 : // thus mask = 1111 0000
217 : if (PMP_GRANULARITY == 0) begin : g_region_addr_mask_zero_granularity
218 : assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT) |
219 : ~&csr_pmp_addr_i[r][b-1:2];
220 : end else begin : g_region_addr_mask_other_granularity
221 : assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT) |
222 : ~&csr_pmp_addr_i[r][b-1:PMP_GRANULARITY+1];
223 : end
224 : end
225 : end
226 : end
227 :
228 : `ifdef RV_USER_MODE
229 874 : logic [PMP_CHANNELS-1:0] pmp_priv_mode_eff;
230 : for (genvar c = 0; c < PMP_CHANNELS; c++) begin : g_priv_mode_eff
231 : assign pmp_priv_mode_eff[c] = (
232 : ((pmp_chan_type[c] == EXEC) & priv_mode_ns) |
233 : ((pmp_chan_type[c] != EXEC) & priv_mode_eff)); // RW affected by mstatus.MPRV
234 : end
235 : `endif
236 :
237 0 : for (genvar c = 0; c < PMP_CHANNELS; c++) begin : g_access_check
238 : assign pmp_req_addr_i[c] = {2'b00, pmp_chan_addr[c]}; // addr. widening: 32-bit -> 34-bit
239 0 : for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_regions
240 : // Comparators are sized according to granularity
241 : assign region_match_eq[c][r] = (pmp_req_addr_i[c][33:PMP_GRANULARITY+2] &
242 : region_addr_mask[r]) ==
243 : (region_start_addr[r][33:PMP_GRANULARITY+2] &
244 : region_addr_mask[r]);
245 : assign region_match_gt[c][r] = pmp_req_addr_i[c][33:PMP_GRANULARITY+2] >
246 : region_start_addr[r][33:PMP_GRANULARITY+2];
247 : assign region_match_lt[c][r] = pmp_req_addr_i[c][33:PMP_GRANULARITY+2] <
248 : csr_pmp_addr_i[r][33:PMP_GRANULARITY+2];
249 :
250 16416 : always_comb begin
251 16416 : region_match_all[c][r] = 1'b0;
252 16416 : unique case (pmp_pmpcfg[r].mode)
253 1262412663 : OFF: region_match_all[c][r] = 1'b0;
254 77241 : NA4: region_match_all[c][r] = region_match_eq[c][r];
255 37419627 : NAPOT: region_match_all[c][r] = region_match_eq[c][r];
256 49278837 : TOR: begin
257 49278837 : region_match_all[c][r] = (region_match_eq[c][r] | region_match_gt[c][r]) &
258 49278837 : region_match_lt[c][r];
259 : end
260 0 : default: region_match_all[c][r] = 1'b0;
261 : endcase
262 : end
263 :
264 : // Basic permission check compares cfg register only.
265 : assign region_basic_perm_check[c][r] =
266 : ((pmp_chan_type[c] == EXEC) & pmp_pmpcfg[r].execute) |
267 : ((pmp_chan_type[c] == WRITE) & pmp_pmpcfg[r].write) |
268 : ((pmp_chan_type[c] == READ) & pmp_pmpcfg[r].read);
269 :
270 : // Check specific required permissions since the behaviour is different
271 : // between Smepmp implementation and original PMP.
272 : assign region_perm_check[c][r] = perm_check_wrapper(
273 : `ifdef RV_SMEPMP
274 : mseccfg,
275 : `else
276 : 3'b000,
277 : `endif
278 : pmp_pmpcfg[r],
279 : pmp_chan_type[c],
280 : `ifdef RV_USER_MODE
281 : pmp_priv_mode_eff[c],
282 : `else
283 : 1'b0,
284 : `endif
285 : region_basic_perm_check[c][r]
286 : );
287 :
288 : // Address bits below PMP granularity (which starts at 4 byte) are deliberately unused.
289 : logic unused_sigs;
290 : assign unused_sigs = ^{region_start_addr[r][PMP_GRANULARITY+2-1:0],
291 : pmp_req_addr_i[c][PMP_GRANULARITY+2-1:0]};
292 : end
293 :
294 : // Once the permission checks of the regions are done, decide if the access is
295 : // denied by figuring out the matching region and its permission check.
296 : assign pmp_chan_err[c] = access_fault_check(
297 : `ifdef RV_SMEPMP
298 : mseccfg,
299 : `else
300 : 3'b000,
301 : `endif
302 : pmp_chan_type[c],
303 : region_match_all[c],
304 : `ifdef RV_USER_MODE
305 : any_region_enabled,
306 : pmp_priv_mode_eff[c],
307 : `else
308 : 1'b0,
309 : 1'b0,
310 : `endif
311 : region_perm_check[c]);
312 :
313 : end
314 :
315 : endmodule // el2_pmp
|