mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-24 14:17:16 -04:00
pma: Check for execute flag on instruction access
When speculation is on it can happen that the core is trying to fetch from a wrong, speculated address. Depending on the SoC this can cause lock-ups. Solution until now was to flush all branchprediction which is quite costly in terms of performance. This commit fixes this and lets the `frontend` check whether the access is actually legal.
This commit is contained in:
parent
6e4a0742ef
commit
90fb1330a9
6 changed files with 51 additions and 9 deletions
|
@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Chcek execute PMA on instruction frontend
|
||||
|
||||
### Changed
|
||||
|
||||
- Re-work interrupt and debug subsystem to associate requests during decode. This improves stability on for non-idempotent loads.
|
||||
|
|
|
@ -33,14 +33,21 @@ package ariane_pkg;
|
|||
// sure to add a propper parameter check to the `check_cfg` function.
|
||||
typedef struct packed {
|
||||
int NrNonIdempotentRules; // Number of non idempotent rules
|
||||
logic [2**16-1:0][63:0] NonIdempotentAddrBase; // base which needs to match
|
||||
logic [2**16-1:0][63:0] NonIdempotentAddrMaks; // bit mask which bits to consider when matching the rule
|
||||
logic [15:0][63:0] NonIdempotentAddrBase; // base which needs to match
|
||||
logic [15:0][63:0] NonIdempotentAddrMaks; // bit mask which bits to consider when matching the rule
|
||||
int NrExecuteRegionRules; // Number of regions which have execute property
|
||||
logic [15:0][63:0] ExecuteRegionAddrBase; // base which needs to match
|
||||
logic [15:0][63:0] ExecuteRegionAddrMaks; // bit mask which bits to consider when matching the rule
|
||||
} ariane_cfg_t;
|
||||
|
||||
localparam ariane_cfg_t ArianeDefaultConfig = '{
|
||||
NrNonIdempotentRules: 2,
|
||||
NonIdempotentAddrBase: {64'b0, 64'b0},
|
||||
NonIdempotentAddrMaks: {64'b0, 64'b0}
|
||||
NonIdempotentAddrMaks: {64'b0, 64'b0},
|
||||
NrExecuteRegionRules: 3,
|
||||
// DRAM, Boot ROM, Debug Module
|
||||
ExecuteRegionAddrBase: {64'h8000_0000, 64'h1_0000, 64'h0},
|
||||
ExecuteRegionAddrMaks: {mask(64'h40000000), mask(64'h10000), mask(64'h1000)}
|
||||
};
|
||||
|
||||
// Function being called to check parameters
|
||||
|
@ -48,10 +55,22 @@ package ariane_pkg;
|
|||
// pragma translate_off
|
||||
`ifndef VERILATOR
|
||||
assert(Cfg.NrNonIdempotentRules <= 16);
|
||||
assert(Cfg.NrExecuteRegionRules <= 16);
|
||||
`endif
|
||||
// pragma translate_on
|
||||
endfunction
|
||||
|
||||
// Generate a mask for a given power of two length
|
||||
function logic [63:0] mask (input logic [63:0] len);
|
||||
// pragma translate_off
|
||||
`ifndef VERILATOR
|
||||
// check that the region we want is actually power of two aligned
|
||||
assert (2**$clog2(len) == len) else $error("Length must be a power of two");
|
||||
`endif
|
||||
// pragma translate_on
|
||||
return {64{1'b1}} << $clog2(len);
|
||||
endfunction
|
||||
|
||||
// TODO: Slowly move those parameters to the new system.
|
||||
localparam NR_SB_ENTRIES = 8; // number of scoreboard entries
|
||||
localparam TRANS_ID_BITS = $clog2(NR_SB_ENTRIES); // depending on the number of scoreboard entries we need that many bits
|
||||
|
|
|
@ -234,7 +234,7 @@ module ariane #(
|
|||
.DmBaseAddress ( DmBaseAddress )
|
||||
) i_frontend (
|
||||
.flush_i ( flush_ctrl_if ), // not entirely correct
|
||||
.flush_bp_i ( flush_ctrl_bp ),
|
||||
.flush_bp_i ( 1'b0 ),
|
||||
.debug_mode_i ( debug_mode ),
|
||||
.boot_addr_i ( boot_addr_i ),
|
||||
.icache_dreq_i ( icache_dreq_cache_if ),
|
||||
|
|
|
@ -251,7 +251,9 @@ module ex_stage #(
|
|||
|
||||
assign lsu_data = lsu_valid_i ? fu_data_i : '0;
|
||||
|
||||
load_store_unit lsu_i (
|
||||
load_store_unit #(
|
||||
.Cfg ( Cfg )
|
||||
) lsu_i (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.flush_i,
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
import ariane_pkg::*;
|
||||
|
||||
module load_store_unit #(
|
||||
parameter int unsigned ASID_WIDTH = 1
|
||||
parameter int unsigned ASID_WIDTH = 1,
|
||||
parameter ariane_pkg::ariane_cfg_t Cfg = ariane_pkg::ArianeDefaultConfig
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
@ -119,7 +120,8 @@ module load_store_unit #(
|
|||
mmu #(
|
||||
.INSTR_TLB_ENTRIES ( 16 ),
|
||||
.DATA_TLB_ENTRIES ( 16 ),
|
||||
.ASID_WIDTH ( ASID_WIDTH )
|
||||
.ASID_WIDTH ( ASID_WIDTH ),
|
||||
.Cfg ( Cfg )
|
||||
) i_mmu (
|
||||
// misaligned bypass
|
||||
.misaligned_ex_i ( misaligned_exception ),
|
||||
|
|
19
src/mmu.sv
19
src/mmu.sv
|
@ -19,8 +19,9 @@ import ariane_pkg::*;
|
|||
module mmu #(
|
||||
parameter int unsigned INSTR_TLB_ENTRIES = 4,
|
||||
parameter int unsigned DATA_TLB_ENTRIES = 4,
|
||||
parameter int unsigned ASID_WIDTH = 1
|
||||
)(
|
||||
parameter int unsigned ASID_WIDTH = 1,
|
||||
parameter ariane_pkg::ariane_cfg_t Cfg = ariane_pkg::ArianeDefaultConfig
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic flush_i,
|
||||
|
@ -178,6 +179,7 @@ module mmu #(
|
|||
//-----------------------
|
||||
// Instruction Interface
|
||||
//-----------------------
|
||||
logic match_any_execute_region;
|
||||
// The instruction interface is a simple request response interface
|
||||
always_comb begin : instr_interface
|
||||
// MMU disabled: just pass through
|
||||
|
@ -235,8 +237,21 @@ module mmu #(
|
|||
icache_areq_o.fetch_exception = {riscv::INSTR_PAGE_FAULT, {25'b0, update_vaddr}, 1'b1};
|
||||
end
|
||||
end
|
||||
// if it didn't match any execute region throw an `Instruction Access Fault`
|
||||
if (!match_any_execute_region) begin
|
||||
icache_areq_o.fetch_exception = {riscv::INSTR_ACCESS_FAULT, icache_areq_o.fetch_paddr, 1'b1};
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin : execute_addr_check
|
||||
// if we don't specify any region we assume everything is accessible
|
||||
match_any_execute_region = (Cfg.NrExecuteRegionRules == 0);
|
||||
// check for execute flag on memory
|
||||
for (int i = 0; i < Cfg.NrExecuteRegionRules; i++) begin
|
||||
match_any_execute_region |= (Cfg.ExecuteRegionAddrBase[i] & Cfg.ExecuteRegionAddrMaks[i])
|
||||
== (icache_areq_o.fetch_paddr & Cfg.ExecuteRegionAddrMaks[i]);
|
||||
end
|
||||
end
|
||||
//-----------------------
|
||||
// Data Interface
|
||||
//-----------------------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue