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 61053036 : input logic clk, // Top level clock
27 316 : input logic rst_l, // Reset
28 0 : input logic scan_mode, // Scan mode
29 :
30 : `ifdef RV_SMEPMP
31 2 : input el2_mseccfg_pkt_t mseccfg, // mseccfg CSR content, RLB, MMWP and MML bits
32 : `endif
33 :
34 : `ifdef RV_USER_MODE
35 841 : input logic priv_mode_ns, // operating privilege mode (next clock cycle)
36 931 : input logic priv_mode_eff, // operating effective privilege mode
37 : `endif
38 :
39 0 : input el2_pmp_cfg_pkt_t pmp_pmpcfg [pt.PMP_ENTRIES],
40 : input logic [31:0] pmp_pmpaddr[pt.PMP_ENTRIES],
41 :
42 592497 : input logic [31:0] pmp_chan_addr[PMP_CHANNELS],
43 769 : input el2_pmp_type_pkt_t pmp_chan_type[PMP_CHANNELS],
44 132801 : output logic pmp_chan_err [PMP_CHANNELS]
45 : );
46 :
47 : logic [ 33:0] csr_pmp_addr_i [pt.PMP_ENTRIES];
48 787800 : logic [ 33:0] pmp_req_addr_i [ PMP_CHANNELS];
49 :
50 : logic [ 33:0] region_start_addr [pt.PMP_ENTRIES];
51 : logic [33:PMP_GRANULARITY+2] region_addr_mask [pt.PMP_ENTRIES];
52 321 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_gt;
53 1 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_lt;
54 637 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_eq;
55 2 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_all;
56 0 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_basic_perm_check;
57 328 : logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_perm_check;
58 :
59 : `ifdef RV_USER_MODE
60 72 : logic any_region_enabled;
61 : `endif
62 :
63 : ///////////////////////
64 : // Functions for PMP //
65 : ///////////////////////
66 :
67 : // Flow of the PMP checking operation follows as below
68 : //
69 : // basic_perm_check ---> perm_check_wrapper ---> orig_perm_check ---/
70 : // |
71 : // region_match_all -----------------> access_fault_check <----------
72 : // |
73 : // \--> pmp_chan_err
74 :
75 : // A wrapper function in which it is decided which form of permission check function gets called
76 15360 : function automatic logic perm_check_wrapper(el2_mseccfg_pkt_t csr_pmp_mseccfg,
77 : el2_pmp_cfg_pkt_t csr_pmp_cfg,
78 : el2_pmp_type_pkt_t req_type,
79 : logic priv_mode,
80 : logic permission_check);
81 :
82 15360 : return csr_pmp_mseccfg.MML ? mml_perm_check(csr_pmp_cfg,
83 15360 : req_type,
84 15360 : priv_mode,
85 15360 : permission_check) :
86 15360 : orig_perm_check(csr_pmp_cfg.lock,
87 15360 : priv_mode,
88 15360 : permission_check);
89 : endfunction
90 :
91 : // Compute permissions checks that apply when MSECCFG.MML is set. Added for Smepmp support.
92 1072272 : function automatic logic mml_perm_check(el2_pmp_cfg_pkt_t csr_pmp_cfg,
93 : el2_pmp_type_pkt_t pmp_req_type,
94 : logic priv_mode,
95 : logic permission_check);
96 : logic result;
97 1072272 : logic unused_cfg = |csr_pmp_cfg.mode;
98 :
99 1072272 : if (!csr_pmp_cfg.read && csr_pmp_cfg.write) begin
100 : // Special-case shared regions where R = 0, W = 1
101 0 : unique case ({csr_pmp_cfg.lock, csr_pmp_cfg.execute})
102 : // Read/write in M, read only in U
103 0 : 2'b00: result =
104 0 : (pmp_req_type == READ) |
105 0 : ((pmp_req_type == WRITE) & ~priv_mode);
106 : // Read/write in M/U
107 0 : 2'b01: result =
108 0 : (pmp_req_type == READ) |
109 0 : (pmp_req_type == WRITE);
110 : // Execute only on M/U
111 0 : 2'b10: result = (pmp_req_type == EXEC);
112 : // Read/execute in M, execute only on U
113 0 : 2'b11: result =
114 0 : (pmp_req_type == EXEC) |
115 0 : ((pmp_req_type == READ) & ~priv_mode);
116 0 : default: ;
117 : endcase
118 1072272 : end else begin
119 1072272 : if (csr_pmp_cfg.read & csr_pmp_cfg.write & csr_pmp_cfg.execute & csr_pmp_cfg.lock) begin
120 : // Special-case shared read only region when R = 1, W = 1, X = 1, L = 1
121 0 : result = (pmp_req_type == READ);
122 1072272 : end else begin
123 : // Otherwise use basic permission check. Permission is always denied if in U mode and
124 : // L is set or if in M mode and L is unset.
125 1072272 : result = permission_check & (priv_mode ? ~csr_pmp_cfg.lock : csr_pmp_cfg.lock);
126 : end
127 : end
128 1072272 : return result;
129 : endfunction
130 :
131 : // Compute permissions checks that apply when MSECCFG.MML is unset. This is the original PMP
132 : // behaviour before Smepmp was added.
133 1290492480 : function automatic logic orig_perm_check(logic pmp_cfg_lock,
134 : logic priv_mode,
135 : logic permission_check);
136 : // For M-mode, any region which matches with the L-bit clear, or with sufficient
137 : // access permissions will be allowed.
138 : // For other modes, the lock bit doesn't matter
139 1290492480 : return priv_mode ? (permission_check) : (~pmp_cfg_lock | permission_check);
140 : endfunction
141 :
142 : // Access fault determination / prioritization
143 960 : function automatic logic access_fault_check(el2_mseccfg_pkt_t csr_pmp_mseccfg,
144 : el2_pmp_type_pkt_t req_type,
145 : logic [pt.PMP_ENTRIES-1:0] match_all,
146 : logic any_region_enabled,
147 : logic priv_mode,
148 : logic [pt.PMP_ENTRIES-1:0] final_perm_check);
149 :
150 : `ifdef RV_USER_MODE
151 : `ifdef RV_SMEPMP
152 : // When MSECCFG.MMWP is set default deny always, otherwise allow for M-mode, deny for other
153 : // modes. Also deny unmatched for M-mode when MSECCFG.MML is set and request type is EXEC.
154 240 : logic access_fail = csr_pmp_mseccfg.MMWP | priv_mode |
155 240 : (csr_pmp_mseccfg.MML && (req_type == EXEC));
156 : `else
157 : // When in user mode and at least one PMP region is enabled deny access by default.
158 : logic access_fail = any_region_enabled & priv_mode;
159 : `endif
160 : `else
161 720 : logic access_fail = 1'b0;
162 : `endif
163 :
164 960 : logic matched = 1'b0;
165 :
166 : // PMP entries are statically prioritized, from 0 to N-1
167 : // The lowest-numbered PMP entry which matches an address determines accessibility
168 960 : for (int r = 0; r < pt.PMP_ENTRIES; r++) begin
169 474885018 : if (!matched && match_all[r]) begin
170 38540010 : access_fail = ~final_perm_check[r];
171 38540010 : matched = 1'b1;
172 : end
173 : end
174 960 : return access_fail;
175 : endfunction
176 :
177 : // ---------------
178 : // Access checking
179 : // ---------------
180 :
181 : `ifdef RV_USER_MODE
182 0 : logic [pt.PMP_ENTRIES-1:0] region_enabled;
183 : for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_reg_ena
184 : assign region_enabled[r] = pmp_pmpcfg[r].mode != OFF;
185 : end
186 : assign any_region_enabled = |region_enabled;
187 : `endif
188 :
189 : for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_addr_exp
190 : assign csr_pmp_addr_i[r] = {
191 : pmp_pmpaddr[r], 2'b00
192 : }; // addr conv.: word @ 32-bit -> byte @ 34-bit
193 : // Start address for TOR matching
194 : if (r == 0) begin : g_entry0
195 : assign region_start_addr[r] = (pmp_pmpcfg[r].mode == TOR) ? 34'h000000000 : csr_pmp_addr_i[r];
196 : end else begin : g_oth
197 : assign region_start_addr[r] = (pmp_pmpcfg[r].mode == TOR) ? csr_pmp_addr_i[r-1] :
198 : csr_pmp_addr_i[r];
199 : end
200 : // Address mask for NA matching
201 : for (genvar b = PMP_GRANULARITY + 2; b < 34; b++) begin : g_bitmask
202 : if (b == 2) begin : g_bit0
203 : // Always mask bit 2 for NAPOT
204 : assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT);
205 : end else begin : g_others
206 : // We will mask this bit if it is within the programmed granule
207 : // i.e. addr = yyyy 0111
208 : // ^
209 : // | This bit pos is the top of the mask, all lower bits set
210 : // thus mask = 1111 0000
211 : if (PMP_GRANULARITY == 0) begin : g_region_addr_mask_zero_granularity
212 : assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT) |
213 : ~&csr_pmp_addr_i[r][b-1:2];
214 : end else begin : g_region_addr_mask_other_granularity
215 : assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT) |
216 : ~&csr_pmp_addr_i[r][b-1:PMP_GRANULARITY+1];
217 : end
218 : end
219 : end
220 : end
221 :
222 : `ifdef RV_USER_MODE
223 849 : logic [PMP_CHANNELS-1:0] pmp_priv_mode_eff;
224 : for (genvar c = 0; c < PMP_CHANNELS; c++) begin : g_priv_mode_eff
225 : assign pmp_priv_mode_eff[c] = (
226 : ((pmp_chan_type[c] == EXEC) & priv_mode_ns) |
227 : ((pmp_chan_type[c] != EXEC) & priv_mode_eff)); // RW affected by mstatus.MPRV
228 : end
229 : `endif
230 :
231 0 : for (genvar c = 0; c < PMP_CHANNELS; c++) begin : g_access_check
232 : assign pmp_req_addr_i[c] = {2'b00, pmp_chan_addr[c]}; // addr. widening: 32-bit -> 34-bit
233 0 : for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_regions
234 : // Comparators are sized according to granularity
235 : assign region_match_eq[c][r] = (pmp_req_addr_i[c][33:PMP_GRANULARITY+2] &
236 : region_addr_mask[r]) ==
237 : (region_start_addr[r][33:PMP_GRANULARITY+2] &
238 : region_addr_mask[r]);
239 : assign region_match_gt[c][r] = pmp_req_addr_i[c][33:PMP_GRANULARITY+2] >
240 : region_start_addr[r][33:PMP_GRANULARITY+2];
241 : assign region_match_lt[c][r] = pmp_req_addr_i[c][33:PMP_GRANULARITY+2] <
242 : csr_pmp_addr_i[r][33:PMP_GRANULARITY+2];
243 :
244 15360 : always_comb begin
245 15360 : region_match_all[c][r] = 1'b0;
246 15360 : unique case (pmp_pmpcfg[r].mode)
247 1071595335 : OFF: region_match_all[c][r] = 1'b0;
248 77241 : NA4: region_match_all[c][r] = region_match_eq[c][r];
249 37419627 : NAPOT: region_match_all[c][r] = region_match_eq[c][r];
250 49543797 : TOR: begin
251 49543797 : region_match_all[c][r] = (region_match_eq[c][r] | region_match_gt[c][r]) &
252 49543797 : region_match_lt[c][r];
253 : end
254 0 : default: region_match_all[c][r] = 1'b0;
255 : endcase
256 : end
257 :
258 : // Basic permission check compares cfg register only.
259 : assign region_basic_perm_check[c][r] =
260 : ((pmp_chan_type[c] == EXEC) & pmp_pmpcfg[r].execute) |
261 : ((pmp_chan_type[c] == WRITE) & pmp_pmpcfg[r].write) |
262 : ((pmp_chan_type[c] == READ) & pmp_pmpcfg[r].read);
263 :
264 : // Check specific required permissions since the behaviour is different
265 : // between Smepmp implementation and original PMP.
266 : assign region_perm_check[c][r] = perm_check_wrapper(
267 : `ifdef RV_SMEPMP
268 : mseccfg,
269 : `else
270 : 3'b000,
271 : `endif
272 : pmp_pmpcfg[r],
273 : pmp_chan_type[c],
274 : `ifdef RV_USER_MODE
275 : pmp_priv_mode_eff[c],
276 : `else
277 : 1'b0,
278 : `endif
279 : region_basic_perm_check[c][r]
280 : );
281 :
282 : // Address bits below PMP granularity (which starts at 4 byte) are deliberately unused.
283 : logic unused_sigs;
284 : assign unused_sigs = ^{region_start_addr[r][PMP_GRANULARITY+2-1:0],
285 : pmp_req_addr_i[c][PMP_GRANULARITY+2-1:0]};
286 : end
287 :
288 : // Once the permission checks of the regions are done, decide if the access is
289 : // denied by figuring out the matching region and its permission check.
290 : assign pmp_chan_err[c] = access_fault_check(
291 : `ifdef RV_SMEPMP
292 : mseccfg,
293 : `else
294 : 3'b000,
295 : `endif
296 : pmp_chan_type[c],
297 : region_match_all[c],
298 : `ifdef RV_USER_MODE
299 : any_region_enabled,
300 : pmp_priv_mode_eff[c],
301 : `else
302 : 1'b0,
303 : 1'b0,
304 : `endif
305 : region_perm_check[c]);
306 :
307 : end
308 :
309 : endmodule // el2_pmp
|