Add pmpcfgm0 register: make regions M-mode without locking them

This commit is contained in:
Luke Wren 2022-08-08 18:34:55 +01:00
parent 65e3d1c48b
commit 92ebbbe95f
2 changed files with 24 additions and 2 deletions

View File

@ -158,6 +158,9 @@ localparam MENVCFG = 12'h30a;
localparam MENVCFGH = 12'h31a;
// Custom M-mode CSRs:
localparam PMPCFGM0 = 12'hbd0; // Make PMP regions M-mode without locking
// bd1 // (reserved for >32 regions)
localparam MEIEA = 12'hbe0; // External interrupt pending array
localparam MEIPA = 12'hbe1; // External interrupt enable array
localparam MEIFA = 12'hbe2; // External interrupt force array

View File

@ -53,6 +53,12 @@ reg pmpcfg_x [0:PMP_REGIONS-1];
// physical address space). We don't implement bits 33 or 32.
reg [W_ADDR-3:0] pmpaddr [0:PMP_REGIONS-1];
// Hazard3 extension for applying PMP regions to M-mode without locking.
// Different from ePMP mseccfg.rlb: low-numbered regions may be locked for
// security reasons, but higher-numbered regions should stll be available for
// other purposes e.g. stack guarding, peripheral emulation
reg [PMP_REGIONS-1:0] pmpcfg_m;
always @ (posedge clk or negedge rst_n) begin: cfg_update
integer i;
if (!rst_n) begin
@ -66,6 +72,7 @@ always @ (posedge clk or negedge rst_n) begin: cfg_update
pmpaddr[i] <= PMP_HARDWIRED[i] ? PMP_HARDWIRED_ADDR[32 * i +: 30] :
PMP_GRAIN > 1 ? ~(~30'h0 << (PMP_GRAIN - 1)) : 30'h0;
end
pmpcfg_m <= {PMP_REGIONS{1'b0}};
end else if (cfg_wen) begin
for (i = 0; i < PMP_REGIONS; i = i + 1) begin
if (cfg_addr == PMPCFG0 + i / 4 && !pmpcfg_l[i]) begin
@ -77,6 +84,7 @@ always @ (posedge clk or negedge rst_n) begin: cfg_update
pmpcfg_w[i] <= PMP_HARDWIRED_CFG[8 * i + 1];
pmpcfg_x[i] <= PMP_HARDWIRED_CFG[8 * i + 0];
pmpaddr[i] <= PMP_HARDWIRED_ADDR[32 * i +: 30];
pmpcfgm[i] <= 1'b0;
end else begin
pmpcfg_l[i] <= cfg_wdata[i % 4 * 8 + 7];
pmpcfg_r[i] <= cfg_wdata[i % 4 * 8 + 2];
@ -97,6 +105,9 @@ always @ (posedge clk or negedge rst_n) begin: cfg_update
end
end
end
if (cfg_addr == PMPCFGM0) begin
pmpcfg_m <= cfg_wdata[PMP_REGIONS-1:0];
end
end
end
@ -126,6 +137,9 @@ always @ (*) begin: cfg_read
end
end
end
if (cfg_addr == PMPCFGM0) begin
cfg_rdata = {{32-PMP_REGIONS{1'b0}}, pmpcfg_m};
end
end
// ----------------------------------------------------------------------------
@ -172,6 +186,7 @@ end
// happen, and we choose alignment fault in this case.
reg d_match;
reg d_m; // Hazard3 extension (M-mode without locking)
reg d_l;
reg d_r;
reg d_w;
@ -180,6 +195,7 @@ reg d_x; // needed because of MXR
always @ (*) begin: check_d_match
integer i;
d_match = 1'b0;
d_m = 1'b0;
d_l = 1'b0;
d_r = 1'b0;
d_w = 1'b0;
@ -189,6 +205,7 @@ always @ (*) begin: check_d_match
for (i = PMP_REGIONS - 1; i >= 0; i = i - 1) begin
if (|pmpcfg_a[i] && (d_addr & match_mask[i]) == match_addr[i]) begin
d_match = 1'b1;
d_m = pmpcfg_m[i];
d_l = pmpcfg_l[i];
d_r = pmpcfg_r[i];
d_w = pmpcfg_w[i];
@ -230,6 +247,7 @@ end
reg i_match;
reg i_partial_match;
reg i_m; // Hazard3 extension (M-mode without locking)
reg i_l;
reg i_x;
@ -248,6 +266,7 @@ always @ (*) begin: check_i_match
if (match_hw0 || match_hw1) begin
i_match = 1'b1;
i_partial_match = (match_hw0 ^ match_hw1) && i_instr_is_32bit;
i_m = pmpcfg_m[i];
i_l = pmpcfg_l[i];
i_x = pmpcfg_x[i];
end
@ -259,7 +278,7 @@ end
// M-mode gets to ignore protections, unless the lock bit is set.
assign d_kill = !(d_m_mode && !d_l) && (
assign d_kill = (!d_m_mode || d_l || d_m) && (
(!d_write && !(d_r || (d_x && mstatus_mxr))) ||
( d_write && !d_w)
);
@ -267,7 +286,7 @@ assign d_kill = !(d_m_mode && !d_l) && (
// Straddling a protection boundary is always an error.
assign i_kill = i_partial_match || (
!(i_m_mode && !i_l) && !i_x
(!i_m_mode || i_l || i_m) && !i_x
);
endmodule