[flash_ctrl] Handle invalid software input
- The software is able to supply an address that is way too
big for flash. Normally this is handled through address
truncation, but this could still result in unexpected
behavior.
- This PR expclitily checks to make sure the supplied address
is not too large for the flash to handle.
Signed-off-by: Timothy Chen <timothytim@google.com>
[flash_ctrl] Add to out of bounds to err code
Signed-off-by: Timothy Chen <timothytim@google.com>
[top] Auto generate
Signed-off-by: Timothy Chen <timothytim@google.com>
[top] Autogen
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl b/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
index 96dfcfe..925a158 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
@@ -136,11 +136,16 @@
logic rd_flash_req;
logic rd_flash_ovfl;
logic [BusAddrW-1:0] rd_flash_addr;
+ logic rd_op_valid;
// Erase Control Connections
logic erase_flash_req;
logic [BusAddrW-1:0] erase_flash_addr;
flash_erase_e erase_flash_type;
+ logic erase_op_valid;
+
+ // combined indication that an operation has started
+ logic op_valid;
// Done / Error signaling from ctrl modules
logic prog_done, rd_done, erase_done;
@@ -194,6 +199,8 @@
logic op_start;
logic [11:0] op_num_words;
logic [BusAddrW-1:0] op_addr;
+ // SW or HW supplied address is out of bounds
+ logic op_addr_oob;
flash_op_e op_type;
flash_part_e op_part;
logic [InfoTypesWidth-1:0] op_info_sel;
@@ -371,6 +378,9 @@
assign op_erase_type = flash_erase_e'(muxed_ctrl.erase_sel.q);
assign op_prog_type = flash_prog_e'(muxed_ctrl.prog_sel.q);
assign op_addr = muxed_addr[BusByteWidth +: BusAddrW];
+ // The supplied address by software is completely beyond the flash
+ // and will wrap. Instead of allowing this, explicitly error back.
+ assign op_addr_oob = muxed_addr >= EndAddr;
assign op_type = flash_op_e'(muxed_ctrl.op.q);
assign op_part = flash_part_e'(muxed_ctrl.partition_sel.q);
assign op_info_sel = muxed_ctrl.info_sel.q;
@@ -378,6 +388,7 @@
assign prog_op = op_type == FlashOpProgram;
assign erase_op = op_type == FlashOpErase;
assign sw_sel = if_sel == SwSel;
+ assign op_valid = prog_op_valid | rd_op_valid | erase_op_valid;
// software privilege to creator seed
assign creator_seed_priv = lc_creator_seed_sw_rw_en == lc_ctrl_pkg::On;
@@ -510,6 +521,7 @@
.op_done_o (prog_done),
.op_err_o (prog_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
.op_type_i (op_prog_type),
.type_avail_i (prog_type_en),
@@ -580,16 +592,18 @@
);
// Read handler is consumer of rd_fifo
+ assign rd_op_valid = op_start & rd_op;
flash_ctrl_rd u_flash_ctrl_rd (
.clk_i,
.rst_ni,
// To arbiter Interface
- .op_start_i (op_start & rd_op),
+ .op_start_i (rd_op_valid),
.op_num_words_i (op_num_words),
.op_done_o (rd_done),
.op_err_o (rd_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
// FIFO Interface
.data_rdy_i (rd_fifo_wready),
@@ -606,13 +620,15 @@
);
// Erase handler does not consume fifo
+ assign erase_op_valid = op_start & erase_op;
flash_ctrl_erase u_flash_ctrl_erase (
// Software Interface
- .op_start_i (op_start & erase_op),
+ .op_start_i (erase_op_valid),
.op_type_i (op_erase_type),
.op_done_o (erase_done),
.op_err_o (erase_err),
.op_addr_i (op_addr),
+ .op_addr_oob_i (op_addr_oob),
// Flash Macro Interface
.flash_req_o (erase_flash_req),
@@ -902,11 +918,13 @@
// Errors and Interrupts
//////////////////////////////////////
+ assign hw2reg.err_code.oob_err.d = 1'b1;
assign hw2reg.err_code.mp_err.d = 1'b1;
assign hw2reg.err_code.ecc_single_err.d = 1'b1;
assign hw2reg.err_code.ecc_multi_err.d = 1'b1;
assign hw2reg.err_code.flash_err.d = 1'b1;
assign hw2reg.err_code.flash_alert.d = 1'b1;
+ assign hw2reg.err_code.oob_err.de = op_valid & op_addr_oob;
assign hw2reg.err_code.mp_err.de = flash_mp_error;
assign hw2reg.err_code.ecc_single_err.de = |flash_phy_rsp.ecc_single_err;
assign hw2reg.err_code.ecc_multi_err.de = |flash_phy_rsp.ecc_multi_err;
@@ -1106,7 +1124,10 @@
.scan_rst_ni
);
+ /////////////////////////////////
// Assertions
+ /////////////////////////////////
+
`ASSERT_KNOWN(TlDValidKnownO_A, core_tl_o.d_valid )
`ASSERT_KNOWN(TlAReadyKnownO_A, core_tl_o.a_ready )
`ASSERT_KNOWN(PrimTlDValidKnownO_A, prim_tl_o.d_valid )
@@ -1124,4 +1145,11 @@
`ASSERT_KNOWN(IntrOpDoneKnownO_A, intr_op_done_o )
`ASSERT_KNOWN(IntrErrO_A, intr_err_o )
+
+
+ // if there is an out of bounds error, flash request should never assert
+ `ASSERT(OutofBoundsReq_A, op_valid & op_addr_oob |-> ~flash_phy_req.req)
+
+ // add more assertions
+
endmodule