Project Full coverage report
Current view: Cores-VeeR-EL2—Cores-VeeR-EL2—design—el2_pmp.sv Coverage Hit Total
Test Date: 19-11-2024 Toggle 84.2% 16 19
Test: all Branch 84.6% 44 52

            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     69889128 :     input logic clk,       // Top level clock
      27          344 :     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              :     input logic             [31:0] pmp_pmpaddr[pt.PMP_ENTRIES],
      43              : 
      44       593777 :     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              :   logic [                33:0]                     csr_pmp_addr_i          [pt.PMP_ENTRIES];
      50       789080 :   logic [                33:0]                     pmp_req_addr_i          [  PMP_CHANNELS];
      51              : 
      52              :   logic [                33:0]                     region_start_addr       [pt.PMP_ENTRIES];
      53              :   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          923 :   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          352 :   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        16512 :   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        16512 :     return csr_pmp_mseccfg.MML ? mml_perm_check(csr_pmp_cfg,
      85        16512 :                                                 req_type,
      86        16512 :                                                 priv_mode,
      87        16512 :                                                 permission_check) :
      88        16512 :                                  orig_perm_check(csr_pmp_cfg.lock,
      89        16512 :                                                  priv_mode,
      90        16512 :                                                  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   2837269008 :   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   2837269008 :     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          270 :     logic access_fail = csr_pmp_mseccfg.MMWP | priv_mode |
     159          270 :                        (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          762 :     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         1032 :     for (int r = 0; r < pt.PMP_ENTRIES; r++) begin
     173   1381208096 :       if (!matched && match_all[r]) begin
     174     86012048 :         access_fail = ~final_perm_check[r];
     175     86012048 :         matched = 1'b1;
     176              :       end
     177              :     end
     178         1032 :     return access_fail;
     179              :   endfunction
     180              : 
     181              :   // ---------------
     182              :   // Access checking
     183              :   // ---------------
     184              : 
     185              : `ifdef RV_USER_MODE
     186            0 :   logic [pt.PMP_ENTRIES-1:0] region_enabled;
     187              :   for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_reg_ena
     188              :     assign region_enabled[r] = pmp_pmpcfg[r].mode != OFF;
     189              :   end
     190              :   assign any_region_enabled = |region_enabled;
     191              : `endif
     192              : 
     193              :   for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_addr_exp
     194              :     assign csr_pmp_addr_i[r] = {
     195              :       pmp_pmpaddr[r], 2'b00
     196              :     };  // addr conv.: word @ 32-bit -> byte @ 34-bit
     197              :     // Start address for TOR matching
     198              :     if (r == 0) begin : g_entry0
     199              :       assign region_start_addr[r] = (pmp_pmpcfg[r].mode == TOR) ? 34'h000000000 : csr_pmp_addr_i[r];
     200              :     end else begin : g_oth
     201              :       assign region_start_addr[r] = (pmp_pmpcfg[r].mode == TOR) ? csr_pmp_addr_i[r-1] :
     202              :                                                                   csr_pmp_addr_i[r];
     203              :     end
     204              :     // Address mask for NA matching
     205              :     for (genvar b = PMP_GRANULARITY + 2; b < 34; b++) begin : g_bitmask
     206              :       if (b == 2) begin : g_bit0
     207              :         // Always mask bit 2 for NAPOT
     208              :         assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT);
     209              :       end else begin : g_others
     210              :         // We will mask this bit if it is within the programmed granule
     211              :         // i.e. addr = yyyy 0111
     212              :         //                  ^
     213              :         //                  | This bit pos is the top of the mask, all lower bits set
     214              :         // thus mask = 1111 0000
     215              :         if (PMP_GRANULARITY == 0) begin : g_region_addr_mask_zero_granularity
     216              :           assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT) |
     217              :                                           ~&csr_pmp_addr_i[r][b-1:2];
     218              :         end else begin : g_region_addr_mask_other_granularity
     219              :           assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT) |
     220              :                                           ~&csr_pmp_addr_i[r][b-1:PMP_GRANULARITY+1];
     221              :         end
     222              :       end
     223              :     end
     224              :   end
     225              : 
     226              : `ifdef RV_USER_MODE
     227          874 :   logic [PMP_CHANNELS-1:0] pmp_priv_mode_eff;
     228              :   for (genvar c = 0; c < PMP_CHANNELS; c++) begin : g_priv_mode_eff
     229              :     assign pmp_priv_mode_eff[c] = (
     230              :       ((pmp_chan_type[c] == EXEC) & priv_mode_ns) |
     231              :       ((pmp_chan_type[c] != EXEC) & priv_mode_eff)); // RW affected by mstatus.MPRV
     232              :   end
     233              : `endif
     234              : 
     235            0 :   for (genvar c = 0; c < PMP_CHANNELS; c++) begin : g_access_check
     236              :     assign pmp_req_addr_i[c] = {2'b00, pmp_chan_addr[c]};  // addr. widening: 32-bit -> 34-bit
     237            0 :     for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_regions
     238              :       // Comparators are sized according to granularity
     239              :       assign region_match_eq[c][r] = (pmp_req_addr_i[c][33:PMP_GRANULARITY+2] &
     240              :                                       region_addr_mask[r]) ==
     241              :                                      (region_start_addr[r][33:PMP_GRANULARITY+2] &
     242              :                                       region_addr_mask[r]);
     243              :       assign region_match_gt[c][r] = pmp_req_addr_i[c][33:PMP_GRANULARITY+2] >
     244              :                                      region_start_addr[r][33:PMP_GRANULARITY+2];
     245              :       assign region_match_lt[c][r] = pmp_req_addr_i[c][33:PMP_GRANULARITY+2] <
     246              :                                      csr_pmp_addr_i[r][33:PMP_GRANULARITY+2];
     247              : 
     248        16512 :       always_comb begin
     249        16512 :         region_match_all[c][r] = 1'b0;
     250        16512 :         unique case (pmp_pmpcfg[r].mode)
     251   1266167706 :           OFF:     region_match_all[c][r] = 1'b0;
     252        77241 :           NA4:     region_match_all[c][r] = region_match_eq[c][r];
     253     37419627 :           NAPOT:   region_match_all[c][r] = region_match_eq[c][r];
     254     49550130 :           TOR: begin
     255     49550130 :             region_match_all[c][r] = (region_match_eq[c][r] | region_match_gt[c][r]) &
     256     49550130 :                                      region_match_lt[c][r];
     257              :           end
     258            0 :           default: region_match_all[c][r] = 1'b0;
     259              :         endcase
     260              :       end
     261              : 
     262              :       // Basic permission check compares cfg register only.
     263              :       assign region_basic_perm_check[c][r] =
     264              :           ((pmp_chan_type[c] == EXEC)  & pmp_pmpcfg[r].execute) |
     265              :           ((pmp_chan_type[c] == WRITE) & pmp_pmpcfg[r].write) |
     266              :           ((pmp_chan_type[c] == READ)  & pmp_pmpcfg[r].read);
     267              : 
     268              :       // Check specific required permissions since the behaviour is different
     269              :       // between Smepmp implementation and original PMP.
     270              :       assign region_perm_check[c][r] = perm_check_wrapper(
     271              : `ifdef RV_SMEPMP
     272              :           mseccfg,
     273              : `else
     274              :           3'b000,
     275              : `endif
     276              :           pmp_pmpcfg[r],
     277              :           pmp_chan_type[c],
     278              : `ifdef RV_USER_MODE
     279              :           pmp_priv_mode_eff[c],
     280              : `else
     281              :           1'b0,
     282              : `endif
     283              :           region_basic_perm_check[c][r]
     284              :       );
     285              : 
     286              :       // Address bits below PMP granularity (which starts at 4 byte) are deliberately unused.
     287              :       logic unused_sigs;
     288              :       assign unused_sigs = ^{region_start_addr[r][PMP_GRANULARITY+2-1:0],
     289              :                              pmp_req_addr_i[c][PMP_GRANULARITY+2-1:0]};
     290              :     end
     291              : 
     292              :     // Once the permission checks of the regions are done, decide if the access is
     293              :     // denied by figuring out the matching region and its permission check.
     294              :     assign pmp_chan_err[c] = access_fault_check(
     295              : `ifdef RV_SMEPMP
     296              :         mseccfg,
     297              : `else
     298              :         3'b000,
     299              : `endif
     300              :         pmp_chan_type[c],
     301              :         region_match_all[c],
     302              : `ifdef RV_USER_MODE
     303              :         any_region_enabled,
     304              :         pmp_priv_mode_eff[c],
     305              : `else
     306              :         1'b0,
     307              :         1'b0,
     308              : `endif
     309              :         region_perm_check[c]);
     310              : 
     311              :   end
     312              : 
     313              : endmodule  // el2_pmp