Skip to content

Commit

Permalink
Introduce logic to extract CFI information for ML-CFI
Browse files Browse the repository at this point in the history
  • Loading branch information
maicolciani committed Sep 21, 2024
1 parent 4cbd3ed commit 3f6aa72
Show file tree
Hide file tree
Showing 11 changed files with 512 additions and 3 deletions.
2 changes: 2 additions & 0 deletions Bender.yml
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ sources:
- core/axi_shim.sv
- core/acc_dispatcher.sv
- core/cva6_rvfi_probes.sv
- core/fifo_dp_v3.sv
- core/ctr_unit.sv

# What is "frontend"?
- core/frontend/btb.sv
Expand Down
8 changes: 7 additions & 1 deletion core/commit_stage.sv
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,13 @@ module commit_stage
// Flush TLBs and pipeline - CONTROLLER
output logic hfence_vvma_o,
// Flush TLBs and pipeline - CONTROLLER
output logic hfence_gvma_o
output logic hfence_gvma_o,
// Control transfer records PC - CTR_UNIT
output riscv::xlen_t [CVA6Cfg.NrCommitPorts-1:0] ctr_source_o,
// Control transfer records type - CTR_UNIT
output riscv::ctr_type_t [CVA6Cfg.NrCommitPorts-1:0] ctr_type_o,
// Control transfer records valid - CTR_UNIT
output logic [CVA6Cfg.NrCommitPorts-1:0] ctr_valid_o
);

// ila_0 i_ila_commit (
Expand Down
131 changes: 131 additions & 0 deletions core/ctr_unit.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright 2024 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Emanuele Parisi, University of Bologna
// Description: Control Transfer Records unit.


module ctr_unit
import ariane_pkg::*;
#(
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty
) (
// Subsystem clock - SUBSYSTEM
input logic clk_i,
// Asynchronous reset active low - SUBSYSTEM
input logic rst_ni,
// Input commit ports
input ctr_commit_port_t ctr_commit_port_1_i,
input ctr_commit_port_t ctr_commit_port_2_i,
// Control Transfer Records source register - CTR_UNIT
output riscv::ctrsource_rv_t emitter_source_o,
// Control Transfer Records target register - CTR_UNIT
output riscv::ctrtarget_rv_t emitter_target_o,
// Control Transfer Records data register - CTR_UNIT
output riscv::ctrdata_rv_t emitter_data_o,
// C2ontrol Transfer Records instr register - CTR_UNIT
output logic [31:0] emitter_instr_o,
// Privilege execution level - CTR_UNIT
output riscv::priv_lvl_t priv_lvl_o
);

// Temporary storage for control transfers with unknown target.
riscv::xlen_t pending_source_d, pending_source_q;
riscv::ctr_type_t pending_type_d, pending_type_q;
logic [31:0] pending_instr_d, pending_instr_q;
riscv::priv_lvl_t pending_priv_lvl_d, pending_priv_lvl_q;
logic pending_valid_d, pending_valid_q;

ctr_commit_port_t ctr_sbe_entry_out;

localparam int ReqFifoWidth = $bits(ctr_commit_port_t) ;
logic fifo_empty, fifo_full;

assign priv_lvl_o = pending_priv_lvl_q;

// Dual port fifo to serialize CVA6 commit ports
fifo_dp_v3 #(
.FALL_THROUGH ( 1'b1 ),
.DATA_WIDTH ( ReqFifoWidth ),
.DEPTH ( 4 )
) dual_port_fifo (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( 1'b0 ),
.testmode_i ( 1'b0 ),
.full_o ( fifo_full ),
.empty_o ( fifo_empty ),
.usage_o ( ),
.data_port_0_i ( ctr_commit_port_1_i ),
.push_port_0_i ( ~fifo_full && ctr_commit_port_1_i.valid ),
.data_port_1_i ( ctr_commit_port_2_i ),
.push_port_1_i ( ~fifo_full && ctr_commit_port_2_i.valid ),
.data_o ( ctr_sbe_entry_out ),
.pop_i ( ~fifo_empty )
);

always_comb begin
// By default, we don't have any control transfer pending.
pending_source_d = 'b0;
pending_type_d = riscv::CTR_TYPE_NONE;
pending_valid_d = 'b0;
pending_instr_d = 'b0;
pending_priv_lvl_d = riscv::PRIV_LVL_M;
if (~(ctr_commit_port_1_i.valid || ctr_commit_port_2_i.valid)) begin
// If no instructions are retired in the current cycle, keep the old values.
pending_source_d = pending_source_q;
pending_type_d = pending_type_q;
pending_valid_d = pending_valid_q;
pending_instr_d = pending_instr_q;
pending_priv_lvl_d = pending_priv_lvl_q;
end else begin
// Record the most recent control transfer with unknown target address.
pending_source_d = ctr_sbe_entry_out.ctr_source;
pending_type_d = ctr_sbe_entry_out.ctr_type;
pending_valid_d = (ctr_commit_port_1_i.valid || ctr_commit_port_2_i.valid);
pending_instr_d = ctr_sbe_entry_out.ctr_instr;
pending_priv_lvl_d = ctr_sbe_entry_out.priv_lvl;
end
end

always_comb begin
emitter_source_o = 'b0;
emitter_target_o = 'b0;
emitter_data_o = 'b0;
emitter_instr_o = 'b0;
if (pending_valid_q && (ctr_commit_port_1_i.valid || ctr_commit_port_2_i.valid)) begin
emitter_source_o.pc = pending_source_q[riscv::XLEN-1:1];
emitter_source_o.v = pending_valid_q;
// The MISP bit is unimplemented.
emitter_target_o.pc = ctr_sbe_entry_out.ctr_source[riscv::XLEN-1:1];
emitter_target_o.misp = 'b0;
// Cycle counting is unimplemented.
emitter_data_o.cftype = pending_type_q;
emitter_instr_o = pending_instr_q;
end
end

always_ff @(posedge clk_i, negedge rst_ni) begin
if (~rst_ni) begin
pending_source_q <= 'b0;
pending_type_q <= riscv::CTR_TYPE_NONE;
pending_instr_q <= 'b0;
pending_valid_q <= 'b0;
pending_priv_lvl_q <= 'b0;
end else begin
pending_source_q <= pending_source_d;
pending_type_q <= pending_type_d;
pending_priv_lvl_q <= pending_priv_lvl_d;
pending_instr_q <= pending_instr_d;
pending_valid_q <= pending_valid_d;
end
end

endmodule
69 changes: 68 additions & 1 deletion core/cva6.sv
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,17 @@ module cva6
// noc request, can be AXI or OpenPiton - SUBSYSTEM
output noc_req_t noc_req_o,
// noc response, can be AXI or OpenPiton - SUBSYSTEM
input noc_resp_t noc_resp_i
input noc_resp_t noc_resp_i,
// Control Transfer Records source register - CTR_UNIT
output riscv::ctrsource_rv_t emitter_source_o,
// Control Transfer Records target register - CTR_UNIT
output riscv::ctrtarget_rv_t emitter_target_o,
// Control Transfer Records data register - CTR_UNIT
output riscv::ctrdata_rv_t emitter_data_o,
// Control Transfer Records instr register - CTR_UNIT
output logic [31:0] emitter_instr_o,
// Privilege execution level - CTR_UNIT
output riscv::priv_lvl_t priv_lvl_o
);

// ------------------------------------------
Expand Down Expand Up @@ -443,6 +453,9 @@ module cva6
riscv::pmpcfg_t [15:0] pmpcfg;
logic [15:0][riscv::PLEN-3:0] pmpaddr;
logic [31:0] mcountinhibit_csr_perf;
riscv::xlen_t [CVA6Cfg.NrCommitPorts-1:0] ctr_source_commit_ctr;
riscv::ctr_type_t [CVA6Cfg.NrCommitPorts-1:0] ctr_type_commit_ctr;
logic [CVA6Cfg.NrCommitPorts-1:0] ctr_valid_commit_ctr;
// ----------------------------
// Performance Counters <-> *
// ----------------------------
Expand Down Expand Up @@ -521,6 +534,12 @@ module cva6
logic inval_valid;
logic inval_ready;

// CTR signals
logic [CVA6Cfg.NrCommitPorts-1:0] ctr_valid;
logic [CVA6Cfg.NrCommitPorts-1:0] [31:0] ctr_instr;
riscv::ctrsource_rv_t [CVA6Cfg.NrCommitPorts-1:0] ctr_source;
riscv::ctrdata_rv_t [CVA6Cfg.NrCommitPorts-1:0] ctr_type;

always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
rst_uarch_n <= 1'b0;
Expand Down Expand Up @@ -912,6 +931,9 @@ module cva6
.hfence_gvma_o (hfence_gvma_commit_controller),
.fence_t_o (fence_t_commit_controller),
.flush_commit_o (flush_commit),
.ctr_source_o (ctr_source_commit_ctr),
.ctr_type_o (ctr_type_commit_ctr),
.ctr_valid_o (ctr_valid_commit_ctr),
.*
);

Expand Down Expand Up @@ -1603,4 +1625,49 @@ module cva6

end //IsRVFI

// ------------------------
// Control Transfer Records
// ------------------------
// Handle data interface to be the control transfer records unit

for(genvar i=0;i<CVA6Cfg.NrCommitPorts;i++) begin
always_comb begin
ctr_valid[i] = commit_instr_id_commit[i].valid & commit_ack;
ctr_instr[i] = commit_instr_id_commit[i].opcode;
ctr_source[i] = commit_instr_id_commit[i].pc;
if (commit_instr_id_commit[i].ex.valid)
ctr_type[i] = riscv::CTR_TYPE_EXC;
else
ctr_type[i] = commit_instr_id_commit[i].cftype;
end
end

ctr_commit_port_t ctr_commit_port_1, ctr_commit_port_2;

assign ctr_commit_port_1 = {
ctr_source: ctr_source[0],
ctr_type : ctr_type[0],
ctr_instr : ctr_instr[0],
priv_lvl : priv_lvl,
valid : ctr_valid[0]
};

assign ctr_commit_port_2 = {
ctr_source: ctr_source[1],
ctr_type : ctr_type[1],
ctr_instr : ctr_instr[1],
priv_lvl : priv_lvl,
valid : ctr_valid[1]
};

ctr_unit #(
.CVA6Cfg(CVA6Cfg)
) i_ctr_unit (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.ctr_commit_port_1_i ( ctr_commit_port_1 ),
.ctr_commit_port_2_i ( ctr_commit_port_2 ),
.*
);

endmodule // ariane
45 changes: 45 additions & 0 deletions core/decoder.sv
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ module decoder
// this instruction needs floating-point rounding-mode verification
logic check_fprm;
riscv::instruction_t instr;
// control transfer type of this instruction
riscv::ctr_type_t control_transfer_type;

assign instr = riscv::instruction_t'(instruction_i);
// transformed instruction
riscv::xlen_t tinst;
Expand Down Expand Up @@ -146,6 +149,7 @@ module decoder
illegal_instr_bm = 1'b0;
illegal_instr_zic = 1'b0;
virtual_illegal_instr = 1'b0;
control_transfer_type = riscv::CTR_TYPE_NONE;
instruction_o.pc = pc_i;
instruction_o.trans_id = '0;
instruction_o.fu = NONE;
Expand All @@ -158,6 +162,7 @@ module decoder
instruction_o.use_zimm = 1'b0;
instruction_o.bp = branch_predict_i;
instruction_o.vfp = 1'b0;
instruction_o.opcode = orig_instr_o;
tinst = '0;
ecall = 1'b0;
ebreak = 1'b0;
Expand Down Expand Up @@ -191,6 +196,7 @@ module decoder
12'b1_0000_0010: begin
if (CVA6Cfg.RVS) begin
instruction_o.op = ariane_pkg::SRET;
control_transfer_type = riscv::CTR_TYPE_TRET;
// check privilege level, SRET can only be executed in S and M mode
// we'll just decode an illegal instruction if we are in the wrong privilege level
if (CVA6Cfg.RVU && priv_lvl_i == riscv::PRIV_LVL_U) begin
Expand Down Expand Up @@ -220,6 +226,7 @@ module decoder
// MRET
12'b11_0000_0010: begin
instruction_o.op = ariane_pkg::MRET;
control_transfer_type = riscv::CTR_TYPE_TRET;
// check privilege level, MRET can only be executed in M mode
// otherwise we decode an illegal instruction
if ((CVA6Cfg.RVS && priv_lvl_i == riscv::PRIV_LVL_S) || (CVA6Cfg.RVU && priv_lvl_i == riscv::PRIV_LVL_U))
Expand Down Expand Up @@ -1352,6 +1359,21 @@ module decoder
imm_select = IIMM;
instruction_o.rd[4:0] = instr.itype.rd;
is_control_flow_instr_o = 1'b1;
if (instr.itype.rd == 5'd1 && instr.itype.rs1 != 5'd5) begin
control_transfer_type = riscv::CTR_TYPE_INDCALL;
end else if (instr.itype.rd == 5'd5 && instr.itype.rs1 != 5'd1) begin
control_transfer_type = riscv::CTR_TYPE_INDCALL;
end else if (instr.itype.rd == 5'd0 && ~(instr.itype.rs1 inside {5'd1, 5'd5})) begin
control_transfer_type = riscv::CTR_TYPE_INDJMP;
end else if (instr.itype.rd == 5'd1 && instr.itype.rs1 == 5'd5) begin
control_transfer_type = riscv::CTR_TYPE_CORSWAP;
end else if (instr.itype.rd == 5'd5 && instr.itype.rs1 == 5'd1) begin
control_transfer_type = riscv::CTR_TYPE_CORSWAP;
end else if (~(instr.itype.rd inside {5'd1, 5'd5}) && (instr.itype.rs1 inside {5'd1, 5'd5})) begin
control_transfer_type = riscv::CTR_TYPE_RET;
end else begin
control_transfer_type = riscv::CTR_TYPE_INDLJMP;
end
// invalid jump and link register -> reserved for vector encoding
if (instr.itype.funct3 != 3'b0) illegal_instr = 1'b1;
end
Expand All @@ -1361,6 +1383,13 @@ module decoder
imm_select = JIMM;
instruction_o.rd[4:0] = instr.utype.rd;
is_control_flow_instr_o = 1'b1;
if (instr.utype.rd inside {5'd1, 5'd5}) begin
control_transfer_type = riscv::CTR_TYPE_DIRCALL;
end else if (instr.utype.rd == 5'd0) begin
control_transfer_type = riscv::CTR_TYPE_DIRJMP;
end else begin
control_transfer_type = riscv::CTR_TYPE_DIRLJMP;
end
end

riscv::OpcodeAuipc: begin
Expand Down Expand Up @@ -1638,4 +1667,20 @@ module decoder
instruction_o.ex.cause = riscv::DEBUG_REQUEST;
end
end

// ------------------------
// Control Transfer Records
// ------------------------
always_comb begin : control_transfer_records
instruction_o.cftype = control_transfer_type;
if (instruction_o.ex.valid) begin
if (instruction_o.ex.cause[riscv::XLEN-1]) begin
instruction_o.cftype = riscv::CTR_TYPE_INTR;
end
else begin
instruction_o.cftype = riscv::CTR_TYPE_EXC;
end
end
end

endmodule
Loading

0 comments on commit 3f6aa72

Please sign in to comment.