Project Full coverage report
Current view: Cores-VeeR-EL2—Cores-VeeR-EL2—design—el2_pmp.sv Coverage Hit Total
Test Date: 19-09-2024 Toggle 80.0% 16 20
Test: all Branch 69.8% 37 53

            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     61851105 :     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          866 :     input logic priv_mode_ns,   // operating privilege mode (next clock cycle)
      36          960 :     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       594235 :     input  logic              [31:0] pmp_chan_addr[PMP_CHANNELS],
      43          769 :     input  el2_pmp_type_pkt_t        pmp_chan_type[PMP_CHANNELS],
      44       138112 :     output logic                     pmp_chan_err [PMP_CHANNELS]
      45              : );
      46              : 
      47              :   logic [                33:0]                     csr_pmp_addr_i          [pt.PMP_ENTRIES];
      48       789538 :   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           75 :   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   1298655216 :   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   1298655216 :     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          258 :     logic access_fail = csr_pmp_mseccfg.MMWP | priv_mode |
     155          258 :                        (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          702 :     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    475872372 :       if (!matched && match_all[r]) begin
     170     39027540 :         access_fail = ~final_perm_check[r];
     171     39027540 :         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          874 :   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   1078080969 :           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     49942851 :           TOR: begin
     251     49942851 :             region_match_all[c][r] = (region_match_eq[c][r] | region_match_gt[c][r]) &
     252     49942851 :                                      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