mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-24 13:57:19 -04:00
[rtl] Add Pointer Authentication
This commit is contained in:
parent
b1ff52dc67
commit
f13ac7b8b9
13 changed files with 579 additions and 64 deletions
|
@ -78,6 +78,12 @@ parameters:
|
|||
paramtype: vlogparam
|
||||
description: "Number of PMP regions"
|
||||
|
||||
PointerAuthentication:
|
||||
datatype: int
|
||||
default: 0
|
||||
paramtype: vlogparam
|
||||
description: "Enable pointer authentication (EXPERIMENTAL) [0/1]"
|
||||
|
||||
targets:
|
||||
sim:
|
||||
default_tool: verilator
|
||||
|
@ -94,6 +100,7 @@ targets:
|
|||
- PMPEnable
|
||||
- PMPGranularity
|
||||
- PMPNumRegions
|
||||
- PointerAuthentication
|
||||
toplevel: ibex_riscv_compliance
|
||||
tools:
|
||||
verilator:
|
||||
|
|
|
@ -24,6 +24,7 @@ module ibex_riscv_compliance (
|
|||
parameter MultiplierImplementation = "fast";
|
||||
parameter bit BranchTargetALU = 1'b0;
|
||||
parameter bit WritebackStage = 1'b0;
|
||||
parameter bit PointerAuthentication = 1'b0;
|
||||
|
||||
logic clk_sys, rst_sys_n;
|
||||
|
||||
|
@ -120,7 +121,8 @@ module ibex_riscv_compliance (
|
|||
.BranchTargetALU (BranchTargetALU ),
|
||||
.WritebackStage (WritebackStage ),
|
||||
.DmHaltAddr (32'h00000000 ),
|
||||
.DmExceptionAddr (32'h00000000 )
|
||||
.DmExceptionAddr (32'h00000000 ),
|
||||
.PointerAuthentication (PointerAuthentication )
|
||||
) u_core (
|
||||
.clk_i (clk_sys ),
|
||||
.rst_ni (rst_sys_n ),
|
||||
|
|
|
@ -88,6 +88,12 @@ parameters:
|
|||
paramtype: vlogparam
|
||||
description: "Number of PMP regions"
|
||||
|
||||
PointerAuthentication:
|
||||
datatype: int
|
||||
default: 0
|
||||
paramtype: vlogparam
|
||||
description: "Enable pointer authentication (EXPERIMENTAL) [0/1]"
|
||||
|
||||
targets:
|
||||
default: &default_target
|
||||
filesets:
|
||||
|
@ -106,7 +112,7 @@ targets:
|
|||
- PMPGranularity
|
||||
- PMPNumRegions
|
||||
- SRAMInitFile
|
||||
|
||||
- PointerAuthentication
|
||||
lint:
|
||||
<<: *default_target
|
||||
default_tool: verilator
|
||||
|
|
|
@ -34,6 +34,7 @@ module ibex_simple_system (
|
|||
parameter bit WritebackStage = 1'b0;
|
||||
parameter MultiplierImplementation = "fast";
|
||||
parameter SRAMInitFile = "";
|
||||
parameter bit PointerAuthentication = 1'b0;
|
||||
|
||||
logic clk_sys = 1'b0, rst_sys_n;
|
||||
|
||||
|
@ -159,7 +160,8 @@ module ibex_simple_system (
|
|||
.WritebackStage ( WritebackStage ),
|
||||
.MultiplierImplementation ( MultiplierImplementation ),
|
||||
.DmHaltAddr ( 32'h00100000 ),
|
||||
.DmExceptionAddr ( 32'h00100000 )
|
||||
.DmExceptionAddr ( 32'h00100000 ),
|
||||
.PointerAuthentication ( PointerAuthentication )
|
||||
) u_core (
|
||||
.clk_i (clk_sys),
|
||||
.rst_ni (rst_sys_n),
|
||||
|
|
|
@ -37,6 +37,8 @@ filesets:
|
|||
# - rtl/ibex_register_file_fpga.sv # FPGA
|
||||
- rtl/ibex_register_file_ff.sv # generic FF-based
|
||||
- rtl/ibex_core.sv
|
||||
- rtl/ibex_pointer_authentication.sv
|
||||
- rtl/ibex_cipher.sv
|
||||
file_type: systemVerilogSource
|
||||
|
||||
files_lint_verilator:
|
||||
|
@ -130,6 +132,12 @@ parameters:
|
|||
paramtype: vlogparam
|
||||
description: "Number of PMP regions"
|
||||
|
||||
PointerAuthentication:
|
||||
datatype: int
|
||||
default: 0
|
||||
paramtype: vlogparam
|
||||
description: "Enable pointer authentication (EXPERIMENTAL) [0/1]"
|
||||
|
||||
targets:
|
||||
default: &default_target
|
||||
filesets:
|
||||
|
|
87
rtl/ibex_cipher.sv
Normal file
87
rtl/ibex_cipher.sv
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// This is just a placeholder for the actual cipher core that will be connected later.
|
||||
module ibex_cipher (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
input logic [127:0] key_i,
|
||||
|
||||
input logic [63:0] in_data_i,
|
||||
input logic in_valid_i,
|
||||
output logic in_ready_o,
|
||||
|
||||
output logic [31:0] out_data_o,
|
||||
output logic out_valid_o,
|
||||
input logic out_ready_i
|
||||
);
|
||||
|
||||
logic [127:0] key_q, key_d;
|
||||
logic [63:0] data_q, data_d;
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
C_INPUT, C_CALC1, C_CALC2, C_CALC3, C_OUTPUT
|
||||
} c_fsm_e;
|
||||
c_fsm_e c_fsm_q, c_fsm_d;
|
||||
|
||||
always_comb begin
|
||||
key_d = key_q;
|
||||
data_d = data_q;
|
||||
in_ready_o = '0;
|
||||
out_data_o = '0;
|
||||
out_valid_o = '0;
|
||||
c_fsm_d = c_fsm_q;
|
||||
|
||||
unique case (c_fsm_q)
|
||||
|
||||
C_INPUT: begin
|
||||
in_ready_o = 1'b1;
|
||||
if (in_valid_i) begin
|
||||
data_d = in_data_i;
|
||||
key_d = key_i;
|
||||
c_fsm_d = C_CALC1;
|
||||
end
|
||||
end
|
||||
|
||||
C_CALC1: begin
|
||||
data_d = key_q[63:0] ^ data_q; // placeholder calculation
|
||||
c_fsm_d = C_CALC2;
|
||||
end
|
||||
C_CALC2: begin
|
||||
data_d = key_q[127:64] ^ data_q; // placeholder calculation
|
||||
c_fsm_d = C_CALC3;
|
||||
end
|
||||
C_CALC3: begin
|
||||
data_d = key_q[63:0] ^ data_q; // placeholder calculation
|
||||
c_fsm_d = C_OUTPUT;
|
||||
end
|
||||
|
||||
C_OUTPUT: begin
|
||||
if (out_ready_i) begin
|
||||
out_data_o = data_q[31:0] ^ data_q[63:32];
|
||||
out_valid_o = 1'b1;
|
||||
c_fsm_d = C_INPUT;
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
c_fsm_d = C_INPUT;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
c_fsm_q <= C_INPUT;
|
||||
key_q <= '0;
|
||||
data_q <= '0;
|
||||
end else begin
|
||||
c_fsm_q <= c_fsm_d;
|
||||
key_q <= key_d;
|
||||
data_q <= data_d;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -33,7 +33,8 @@ module ibex_core #(
|
|||
parameter bit DbgTriggerEn = 1'b0,
|
||||
parameter bit SecureIbex = 1'b0,
|
||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
||||
parameter int unsigned DmExceptionAddr = 32'h1A110808,
|
||||
parameter bit PointerAuthentication = 1'b0
|
||||
) (
|
||||
// Clock and Reset
|
||||
input logic clk_i,
|
||||
|
@ -344,6 +345,16 @@ module ibex_core #(
|
|||
logic [31:0] rvfi_mem_addr_q;
|
||||
`endif
|
||||
|
||||
// Pointer Authentication
|
||||
logic pa_pac_en;
|
||||
logic pa_aut_en;
|
||||
logic [31:0] pa_data0;
|
||||
logic [31:0] pa_data1;
|
||||
logic pa_ready_id;
|
||||
logic [31:0] pa_result;
|
||||
logic pa_valid;
|
||||
logic [127:0] csr_pa_key;
|
||||
|
||||
//////////////////////
|
||||
// Clock management //
|
||||
//////////////////////
|
||||
|
@ -467,13 +478,14 @@ module ibex_core #(
|
|||
//////////////
|
||||
|
||||
ibex_id_stage #(
|
||||
.RV32E ( RV32E ),
|
||||
.RV32M ( RV32M ),
|
||||
.RV32B ( RV32B ),
|
||||
.BranchTargetALU ( BranchTargetALU ),
|
||||
.DataIndTiming ( DataIndTiming ),
|
||||
.SpecBranch ( SpecBranch ),
|
||||
.WritebackStage ( WritebackStage )
|
||||
.RV32E ( RV32E ),
|
||||
.RV32M ( RV32M ),
|
||||
.RV32B ( RV32B ),
|
||||
.BranchTargetALU ( BranchTargetALU ),
|
||||
.DataIndTiming ( DataIndTiming ),
|
||||
.SpecBranch ( SpecBranch ),
|
||||
.WritebackStage ( WritebackStage ),
|
||||
.PointerAuthentication ( PointerAuthentication )
|
||||
) id_stage_i (
|
||||
.clk_i ( clk ),
|
||||
.rst_ni ( rst_ni ),
|
||||
|
@ -616,7 +628,16 @@ module ibex_core #(
|
|||
.perf_mul_wait_o ( perf_mul_wait ),
|
||||
.perf_div_wait_o ( perf_div_wait ),
|
||||
.instr_id_done_o ( instr_id_done ),
|
||||
.instr_id_done_compressed_o ( instr_id_done_compressed )
|
||||
.instr_id_done_compressed_o ( instr_id_done_compressed ),
|
||||
|
||||
// Pointer Authentication
|
||||
.pac_en_dec_o ( pa_pac_en ),
|
||||
.aut_en_dec_o ( pa_aut_en ),
|
||||
.pa_data0_o ( pa_data0 ),
|
||||
.pa_data1_o ( pa_data1 ),
|
||||
.pa_ready_id_o ( pa_ready_id ),
|
||||
.pa_result_i ( pa_result ),
|
||||
.pa_valid_i ( pa_valid )
|
||||
);
|
||||
|
||||
// for RVFI only
|
||||
|
@ -906,17 +927,18 @@ module ibex_core #(
|
|||
assign csr_addr = csr_num_e'(csr_access ? alu_operand_b_ex[11:0] : 12'b0);
|
||||
|
||||
ibex_cs_registers #(
|
||||
.DbgTriggerEn ( DbgTriggerEn ),
|
||||
.DataIndTiming ( DataIndTiming ),
|
||||
.DummyInstructions ( DummyInstructions ),
|
||||
.ICache ( ICache ),
|
||||
.MHPMCounterNum ( MHPMCounterNum ),
|
||||
.MHPMCounterWidth ( MHPMCounterWidth ),
|
||||
.PMPEnable ( PMPEnable ),
|
||||
.PMPGranularity ( PMPGranularity ),
|
||||
.PMPNumRegions ( PMPNumRegions ),
|
||||
.RV32E ( RV32E ),
|
||||
.RV32M ( RV32M )
|
||||
.DbgTriggerEn ( DbgTriggerEn ),
|
||||
.DataIndTiming ( DataIndTiming ),
|
||||
.DummyInstructions ( DummyInstructions ),
|
||||
.ICache ( ICache ),
|
||||
.MHPMCounterNum ( MHPMCounterNum ),
|
||||
.MHPMCounterWidth ( MHPMCounterWidth ),
|
||||
.PMPEnable ( PMPEnable ),
|
||||
.PMPGranularity ( PMPGranularity ),
|
||||
.PMPNumRegions ( PMPNumRegions ),
|
||||
.RV32E ( RV32E ),
|
||||
.RV32M ( RV32M ),
|
||||
.PointerAuthentication ( PointerAuthentication )
|
||||
) cs_registers_i (
|
||||
.clk_i ( clk ),
|
||||
.rst_ni ( rst_ni ),
|
||||
|
@ -956,6 +978,9 @@ module ibex_core #(
|
|||
.csr_pmp_cfg_o ( csr_pmp_cfg ),
|
||||
.csr_pmp_addr_o ( csr_pmp_addr ),
|
||||
|
||||
// Pointer Authenticaiton
|
||||
.csr_pa_key_o ( csr_pa_key ),
|
||||
|
||||
// debug
|
||||
.csr_depc_o ( csr_depc ),
|
||||
.debug_mode_i ( debug_mode ),
|
||||
|
@ -1385,4 +1410,36 @@ module ibex_core #(
|
|||
|
||||
`endif
|
||||
|
||||
if (PointerAuthentication) begin : g_pa
|
||||
ibex_pointer_authentication pointer_authentication_i (
|
||||
.clk_i ( clk ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.csr_pa_key_i ( csr_pa_key ),
|
||||
.pac_en_i ( pa_pac_en ),
|
||||
.aut_en_i ( pa_aut_en ),
|
||||
.pa_data0_i ( pa_data0 ),
|
||||
.pa_data1_i ( pa_data1 ),
|
||||
.pa_ready_id_i ( pa_ready_id ),
|
||||
.pa_result_o ( pa_result ),
|
||||
.pa_valid_o ( pa_valid )
|
||||
);
|
||||
end else begin : g_no_pa
|
||||
logic unused_pa_pac_en;
|
||||
logic unused_pa_aut_en;
|
||||
logic [31:0] unused_pa_data0;
|
||||
logic [31:0] unused_pa_data1;
|
||||
logic unused_pa_ready_id;
|
||||
logic [127:0] unused_csr_pa_key;
|
||||
assign unused_pa_pac_en = pa_pac_en;
|
||||
assign unused_pa_aut_en = pa_aut_en;
|
||||
assign unused_pa_data0 = pa_data0;
|
||||
assign unused_pa_data1 = pa_data1;
|
||||
assign unused_pa_ready_id = pa_ready_id;
|
||||
assign unused_csr_pa_key = csr_pa_key;
|
||||
|
||||
// Output tieoff
|
||||
assign pa_result = '0;
|
||||
assign pa_valid = '0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -27,7 +27,8 @@ module ibex_core_tracing #(
|
|||
parameter bit DbgTriggerEn = 1'b0,
|
||||
parameter bit SecureIbex = 1'b0,
|
||||
parameter int unsigned DmHaltAddr = 32'h1A110800,
|
||||
parameter int unsigned DmExceptionAddr = 32'h1A110808
|
||||
parameter int unsigned DmExceptionAddr = 32'h1A110808,
|
||||
parameter bit PointerAuthentication = 1'b0
|
||||
) (
|
||||
// Clock and Reset
|
||||
input logic clk_i,
|
||||
|
@ -123,7 +124,8 @@ module ibex_core_tracing #(
|
|||
.WritebackStage ( WritebackStage ),
|
||||
.SecureIbex ( SecureIbex ),
|
||||
.DmHaltAddr ( DmHaltAddr ),
|
||||
.DmExceptionAddr ( DmExceptionAddr )
|
||||
.DmExceptionAddr ( DmExceptionAddr ),
|
||||
.PointerAuthentication ( PointerAuthentication )
|
||||
) u_ibex_core (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
|
|
@ -13,17 +13,18 @@
|
|||
`include "prim_assert.sv"
|
||||
|
||||
module ibex_cs_registers #(
|
||||
parameter bit DbgTriggerEn = 0,
|
||||
parameter bit DataIndTiming = 1'b0,
|
||||
parameter bit DummyInstructions = 1'b0,
|
||||
parameter bit ICache = 1'b0,
|
||||
parameter int unsigned MHPMCounterNum = 10,
|
||||
parameter int unsigned MHPMCounterWidth = 40,
|
||||
parameter bit PMPEnable = 0,
|
||||
parameter int unsigned PMPGranularity = 0,
|
||||
parameter int unsigned PMPNumRegions = 4,
|
||||
parameter bit RV32E = 0,
|
||||
parameter bit RV32M = 0
|
||||
parameter bit DbgTriggerEn = 0,
|
||||
parameter bit DataIndTiming = 1'b0,
|
||||
parameter bit DummyInstructions = 1'b0,
|
||||
parameter bit ICache = 1'b0,
|
||||
parameter int unsigned MHPMCounterNum = 10,
|
||||
parameter int unsigned MHPMCounterWidth = 40,
|
||||
parameter bit PMPEnable = 0,
|
||||
parameter int unsigned PMPGranularity = 0,
|
||||
parameter int unsigned PMPNumRegions = 4,
|
||||
parameter bit RV32E = 0,
|
||||
parameter bit RV32M = 0,
|
||||
parameter bit PointerAuthentication = 0
|
||||
) (
|
||||
// Clock and Reset
|
||||
input logic clk_i,
|
||||
|
@ -66,6 +67,9 @@ module ibex_cs_registers #(
|
|||
output ibex_pkg::pmp_cfg_t csr_pmp_cfg_o [PMPNumRegions],
|
||||
output logic [33:0] csr_pmp_addr_o [PMPNumRegions],
|
||||
|
||||
// Pointer Authentication
|
||||
output logic [127:0] csr_pa_key_o,
|
||||
|
||||
// debug
|
||||
input logic debug_mode_i,
|
||||
input ibex_pkg::dbg_cause_e debug_cause_i,
|
||||
|
@ -199,6 +203,9 @@ module ibex_cs_registers #(
|
|||
logic [31:0] pmp_addr_rdata [PMP_MAX_REGIONS];
|
||||
logic [PMP_CFG_W-1:0] pmp_cfg_rdata [PMP_MAX_REGIONS];
|
||||
|
||||
// Key for Pointer Authentication
|
||||
logic [127:0] pa_key;
|
||||
|
||||
// Hardware performance monitor signals
|
||||
logic [31:0] mcountinhibit;
|
||||
// Only have mcountinhibit flops for counters that actually exist
|
||||
|
@ -431,6 +438,11 @@ module ibex_cs_registers #(
|
|||
csr_rdata_int = '0;
|
||||
end
|
||||
|
||||
// Custom CSR for Pointer Authentication (cannot be read)
|
||||
CSR_PAKEY0, CSR_PAKEY1, CSR_PAKEY2, CSR_PAKEY3: begin
|
||||
csr_rdata_int = '0;
|
||||
end
|
||||
|
||||
default: begin
|
||||
illegal_csr = 1'b1;
|
||||
end
|
||||
|
@ -855,6 +867,36 @@ module ibex_cs_registers #(
|
|||
end
|
||||
end
|
||||
|
||||
////////////////////////////
|
||||
// Pointer Authentication //
|
||||
////////////////////////////
|
||||
|
||||
if (PointerAuthentication) begin : g_pa_key
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
pa_key <= '0;
|
||||
end else begin
|
||||
if (csr_we_int && (csr_addr == CSR_PAKEY0)) begin
|
||||
pa_key[31:0] <= csr_wdata_int;
|
||||
end
|
||||
if (csr_we_int && (csr_addr == CSR_PAKEY1)) begin
|
||||
pa_key[63:32] <= csr_wdata_int;
|
||||
end
|
||||
if (csr_we_int && (csr_addr == CSR_PAKEY2)) begin
|
||||
pa_key[95:64] <= csr_wdata_int;
|
||||
end
|
||||
if (csr_we_int && (csr_addr == CSR_PAKEY3)) begin
|
||||
pa_key[127:96] <= csr_wdata_int;
|
||||
end
|
||||
end
|
||||
end
|
||||
end else begin : g_no_pa_key
|
||||
// Generate tieoff when PointerAuthentication is not configured
|
||||
assign pa_key = '0;
|
||||
end
|
||||
|
||||
assign csr_pa_key_o = pa_key;
|
||||
|
||||
//////////////////////////
|
||||
// Performance monitor //
|
||||
//////////////////////////
|
||||
|
|
|
@ -14,10 +14,11 @@
|
|||
`include "prim_assert.sv"
|
||||
|
||||
module ibex_decoder #(
|
||||
parameter bit RV32E = 0,
|
||||
parameter bit RV32M = 1,
|
||||
parameter bit BranchTargetALU = 0,
|
||||
parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone
|
||||
parameter bit RV32E = 0,
|
||||
parameter bit RV32M = 1,
|
||||
parameter bit BranchTargetALU = 0,
|
||||
parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone,
|
||||
parameter bit PointerAuthentication = 0
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
@ -94,7 +95,11 @@ module ibex_decoder #(
|
|||
|
||||
// jump/branches
|
||||
output logic jump_in_dec_o, // jump is being calculated in ALU
|
||||
output logic branch_in_dec_o
|
||||
output logic branch_in_dec_o,
|
||||
|
||||
// Pointer Authentication
|
||||
output logic pac_en_dec_o,
|
||||
output logic aut_en_dec_o
|
||||
);
|
||||
|
||||
import ibex_pkg::*;
|
||||
|
@ -115,6 +120,9 @@ module ibex_decoder #(
|
|||
logic use_rs3_d;
|
||||
logic use_rs3_q;
|
||||
|
||||
logic pa_use_rs3;
|
||||
logic pa_write_to_rs1;
|
||||
|
||||
csr_op_e csr_op;
|
||||
|
||||
opcode_e opcode;
|
||||
|
@ -154,11 +162,11 @@ module ibex_decoder #(
|
|||
assign instr_rs2 = instr[24:20];
|
||||
assign instr_rs3 = instr[31:27];
|
||||
assign rf_raddr_a_o = (use_rs3_q & ~instr_first_cycle_i) ? instr_rs3 : instr_rs1; // rs3 / rs1
|
||||
assign rf_raddr_b_o = instr_rs2; // rs2
|
||||
assign rf_raddr_b_o = pa_use_rs3 ? instr_rs3 : instr_rs2; // rs3 / rs2
|
||||
|
||||
// destination register
|
||||
assign instr_rd = instr[11:7];
|
||||
assign rf_waddr_o = instr_rd; // rd
|
||||
assign rf_waddr_o = pa_write_to_rs1 ? instr_rs1 : instr_rd; // rs1 / rd
|
||||
|
||||
////////////////////
|
||||
// Register check //
|
||||
|
@ -219,6 +227,11 @@ module ibex_decoder #(
|
|||
ecall_insn_o = 1'b0;
|
||||
wfi_insn_o = 1'b0;
|
||||
|
||||
pac_en_dec_o = 1'b0;
|
||||
aut_en_dec_o = 1'b0;
|
||||
pa_use_rs3 = 1'b0;
|
||||
pa_write_to_rs1 = 1'b0;
|
||||
|
||||
opcode = opcode_e'(instr[6:0]);
|
||||
|
||||
unique case (opcode)
|
||||
|
@ -612,6 +625,45 @@ module ibex_decoder #(
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
////////////////////////////
|
||||
// Pointer Authentication //
|
||||
////////////////////////////
|
||||
|
||||
OPCODE_PA: begin // Custom Operations for Pointer Authentication
|
||||
unique case (instr[14:12])
|
||||
3'b000: begin // PAC
|
||||
pac_en_dec_o = (PointerAuthentication) ? 1'b1 : 1'b0;
|
||||
rf_wdata_sel_o = RF_WD_PA;
|
||||
rf_we = 1'b1;
|
||||
if (instr_first_cycle_i) begin
|
||||
// First write magic number and LSBs of pointer to rs1
|
||||
pa_write_to_rs1 = 1'b1;
|
||||
end else begin
|
||||
// Then write MSBs of pointer and pac to rd
|
||||
pa_write_to_rs1 = 1'b0;
|
||||
end
|
||||
illegal_insn = (PointerAuthentication) ? 1'b0 : 1'b1;
|
||||
end
|
||||
|
||||
3'b001: begin // AUT
|
||||
aut_en_dec_o = (PointerAuthentication) ? 1'b1 : 1'b0;
|
||||
rf_wdata_sel_o = RF_WD_PA;
|
||||
rf_we = 1'b1;
|
||||
if (instr_first_cycle_i) begin
|
||||
// First read MSBs of pointer and pac from rs2
|
||||
pa_use_rs3 = 1'b0;
|
||||
end else begin
|
||||
// Then read LSBs of pointer from rs1 and read context from rs3
|
||||
pa_use_rs3 = 1'b1;
|
||||
end
|
||||
illegal_insn = (PointerAuthentication) ? 1'b0 : 1'b1;
|
||||
end
|
||||
|
||||
default:
|
||||
illegal_insn = 1'b1;
|
||||
endcase
|
||||
end
|
||||
default: begin
|
||||
illegal_insn = 1'b1;
|
||||
end
|
||||
|
|
|
@ -17,13 +17,14 @@
|
|||
`include "prim_assert.sv"
|
||||
|
||||
module ibex_id_stage #(
|
||||
parameter bit RV32E = 0,
|
||||
parameter bit RV32M = 1,
|
||||
parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone,
|
||||
parameter bit DataIndTiming = 1'b0,
|
||||
parameter bit BranchTargetALU = 0,
|
||||
parameter bit SpecBranch = 0,
|
||||
parameter bit WritebackStage = 0
|
||||
parameter bit RV32E = 0,
|
||||
parameter bit RV32M = 1,
|
||||
parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone,
|
||||
parameter bit DataIndTiming = 1'b0,
|
||||
parameter bit BranchTargetALU = 0,
|
||||
parameter bit SpecBranch = 0,
|
||||
parameter bit WritebackStage = 0,
|
||||
parameter bit PointerAuthentication = 0
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
@ -177,7 +178,16 @@ module ibex_id_stage #(
|
|||
output logic perf_mul_wait_o,
|
||||
output logic perf_div_wait_o,
|
||||
output logic instr_id_done_o,
|
||||
output logic instr_id_done_compressed_o
|
||||
output logic instr_id_done_compressed_o,
|
||||
|
||||
// Pointer Authentication
|
||||
output logic pac_en_dec_o,
|
||||
output logic aut_en_dec_o,
|
||||
output logic [31:0] pa_data0_o,
|
||||
output logic [31:0] pa_data1_o,
|
||||
output logic pa_ready_id_o,
|
||||
input logic [31:0] pa_result_i,
|
||||
input logic pa_valid_i
|
||||
);
|
||||
|
||||
import ibex_pkg::*;
|
||||
|
@ -273,6 +283,10 @@ module ibex_id_stage #(
|
|||
logic [31:0] alu_operand_a;
|
||||
logic [31:0] alu_operand_b;
|
||||
|
||||
// Pointer Authentication
|
||||
logic pa_en_dec;
|
||||
logic stall_pa;
|
||||
|
||||
/////////////
|
||||
// LSU Mux //
|
||||
/////////////
|
||||
|
@ -401,6 +415,7 @@ module ibex_id_stage #(
|
|||
unique case (rf_wdata_sel)
|
||||
RF_WD_EX: rf_wdata_id_o = result_ex_i;
|
||||
RF_WD_CSR: rf_wdata_id_o = csr_rdata_i;
|
||||
RF_WD_PA: rf_wdata_id_o = pa_result_i;
|
||||
default: rf_wdata_id_o = result_ex_i;
|
||||
endcase;
|
||||
end
|
||||
|
@ -410,10 +425,11 @@ module ibex_id_stage #(
|
|||
/////////////
|
||||
|
||||
ibex_decoder #(
|
||||
.RV32E ( RV32E ),
|
||||
.RV32M ( RV32M ),
|
||||
.RV32B ( RV32B ),
|
||||
.BranchTargetALU ( BranchTargetALU )
|
||||
.RV32E ( RV32E ),
|
||||
.RV32M ( RV32M ),
|
||||
.RV32B ( RV32B ),
|
||||
.BranchTargetALU ( BranchTargetALU ),
|
||||
.PointerAuthentication (PointerAuthentication )
|
||||
) decoder_i (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
|
@ -484,7 +500,11 @@ module ibex_id_stage #(
|
|||
|
||||
// jump/branches
|
||||
.jump_in_dec_o ( jump_in_dec ),
|
||||
.branch_in_dec_o ( branch_in_dec )
|
||||
.branch_in_dec_o ( branch_in_dec ),
|
||||
|
||||
// Pointer Authentication
|
||||
.pac_en_dec_o ( pac_en_dec_o ),
|
||||
.aut_en_dec_o ( aut_en_dec_o )
|
||||
);
|
||||
|
||||
/////////////////////////////////
|
||||
|
@ -638,6 +658,8 @@ module ibex_id_stage #(
|
|||
assign multdiv_operand_a_ex_o = rf_rdata_a_fwd;
|
||||
assign multdiv_operand_b_ex_o = rf_rdata_b_fwd;
|
||||
|
||||
assign pa_en_dec = pac_en_dec_o | aut_en_dec_o;
|
||||
|
||||
////////////////////////
|
||||
// Branch set control //
|
||||
////////////////////////
|
||||
|
@ -723,6 +745,7 @@ module ibex_id_stage #(
|
|||
stall_jump = 1'b0;
|
||||
stall_branch = 1'b0;
|
||||
stall_alu = 1'b0;
|
||||
stall_pa = 1'b0;
|
||||
branch_set_d = 1'b0;
|
||||
branch_spec = 1'b0;
|
||||
jump_set = 1'b0;
|
||||
|
@ -776,6 +799,22 @@ module ibex_id_stage #(
|
|||
id_fsm_d = MULTI_CYCLE;
|
||||
rf_we_raw = 1'b0;
|
||||
end
|
||||
pa_en_dec: begin
|
||||
if (pac_en_dec_o) begin // PAC
|
||||
if (ready_wb_i) begin
|
||||
id_fsm_d = MULTI_CYCLE;
|
||||
rf_we_raw = 1'b1;
|
||||
end else begin
|
||||
// Wait until the writeback stage is ready
|
||||
id_fsm_d = FIRST_CYCLE;
|
||||
rf_we_raw = 1'b0;
|
||||
end
|
||||
end else begin // AUT
|
||||
id_fsm_d = MULTI_CYCLE;
|
||||
rf_we_raw = 1'b0;
|
||||
end
|
||||
stall_pa = 1'b1;
|
||||
end
|
||||
default: begin
|
||||
id_fsm_d = FIRST_CYCLE;
|
||||
end
|
||||
|
@ -787,12 +826,17 @@ module ibex_id_stage #(
|
|||
rf_we_raw = rf_we_dec & ex_valid_i;
|
||||
end
|
||||
|
||||
if (pa_en_dec) begin
|
||||
rf_we_raw = rf_we_dec & pa_valid_i;
|
||||
end
|
||||
|
||||
if (multicycle_done & ready_wb_i) begin
|
||||
id_fsm_d = FIRST_CYCLE;
|
||||
end else begin
|
||||
stall_multdiv = multdiv_en_dec;
|
||||
stall_branch = branch_in_dec;
|
||||
stall_jump = jump_in_dec;
|
||||
stall_pa = pa_en_dec;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -805,12 +849,13 @@ module ibex_id_stage #(
|
|||
|
||||
// Note for the two-stage configuration ready_wb_i is always set
|
||||
assign multdiv_ready_id_o = ready_wb_i;
|
||||
assign pa_ready_id_o = ready_wb_i;
|
||||
|
||||
`ASSERT(StallIDIfMulticycle, (id_fsm_q == FIRST_CYCLE) & (id_fsm_d == MULTI_CYCLE) |-> stall_id)
|
||||
|
||||
// Stall ID/EX stage for reason that relates to instruction in ID/EX
|
||||
assign stall_id = stall_ld_hz | stall_mem | stall_multdiv | stall_jump | stall_branch |
|
||||
stall_alu;
|
||||
stall_alu | stall_pa;
|
||||
|
||||
assign instr_done = ~stall_id & ~flush_id & instr_executing;
|
||||
|
||||
|
@ -833,7 +878,8 @@ module ibex_id_stage #(
|
|||
|
||||
logic instr_kill;
|
||||
|
||||
assign multicycle_done = lsu_req_dec ? ~stall_mem : ex_valid_i;
|
||||
assign multicycle_done = lsu_req_dec ? ~stall_mem :
|
||||
pa_en_dec ? pa_valid_i : ex_valid_i;
|
||||
|
||||
// Is a memory access ongoing that isn't finishing this cycle
|
||||
assign outstanding_memory_access = (outstanding_load_wb_i | outstanding_store_wb_i) &
|
||||
|
@ -910,7 +956,7 @@ module ibex_id_stage #(
|
|||
lsu_we ? WB_INSTR_STORE :
|
||||
WB_INSTR_LOAD;
|
||||
|
||||
assign en_wb_o = instr_done;
|
||||
assign en_wb_o = instr_done | (pac_en_dec_o & instr_first_cycle);
|
||||
|
||||
assign instr_id_done_o = en_wb_o & ready_wb_i;
|
||||
|
||||
|
@ -921,7 +967,8 @@ module ibex_id_stage #(
|
|||
(outstanding_memory_access | stall_ld_hz);
|
||||
end else begin : gen_no_stall_mem
|
||||
|
||||
assign multicycle_done = lsu_req_dec ? lsu_resp_valid_i : ex_valid_i;
|
||||
assign multicycle_done = lsu_req_dec ? lsu_resp_valid_i :
|
||||
pa_en_dec ? pa_valid_i : ex_valid_i;
|
||||
|
||||
assign data_req_allowed = instr_first_cycle;
|
||||
|
||||
|
@ -981,6 +1028,9 @@ module ibex_id_stage #(
|
|||
|
||||
assign instr_id_done_compressed_o = instr_id_done_o & instr_is_compressed_i;
|
||||
|
||||
assign pa_data0_o = rf_rdata_a_fwd;
|
||||
assign pa_data1_o = rf_rdata_b_fwd;
|
||||
|
||||
////////////////
|
||||
// Assertions //
|
||||
////////////////
|
||||
|
@ -1004,7 +1054,8 @@ module ibex_id_stage #(
|
|||
IMM_B_INCR_PC})
|
||||
`ASSERT(IbexRegfileWdataSelValid, instr_valid_i |-> rf_wdata_sel inside {
|
||||
RF_WD_EX,
|
||||
RF_WD_CSR})
|
||||
RF_WD_CSR,
|
||||
RF_WD_PA})
|
||||
`ASSERT_KNOWN(IbexWbStateKnown, id_fsm_q)
|
||||
|
||||
// Branch decision must be valid when jumping.
|
||||
|
|
|
@ -24,6 +24,7 @@ typedef enum integer {
|
|||
|
||||
typedef enum logic [6:0] {
|
||||
OPCODE_LOAD = 7'h03,
|
||||
OPCODE_PA = 7'h0b,
|
||||
OPCODE_MISC_MEM = 7'h0f,
|
||||
OPCODE_OP_IMM = 7'h13,
|
||||
OPCODE_AUIPC = 7'h17,
|
||||
|
@ -224,9 +225,10 @@ typedef enum logic [2:0] {
|
|||
} imm_b_sel_e;
|
||||
|
||||
// Regfile write data selection
|
||||
typedef enum logic {
|
||||
typedef enum logic [1:0] {
|
||||
RF_WD_EX,
|
||||
RF_WD_CSR
|
||||
RF_WD_CSR,
|
||||
RF_WD_PA
|
||||
} rf_wd_sel_e;
|
||||
|
||||
//////////////
|
||||
|
@ -466,7 +468,11 @@ typedef enum logic[11:0] {
|
|||
CSR_MHPMCOUNTER30H = 12'hB9E,
|
||||
CSR_MHPMCOUNTER31H = 12'hB9F,
|
||||
CSR_CPUCTRL = 12'h7C0,
|
||||
CSR_SECURESEED = 12'h7C1
|
||||
CSR_SECURESEED = 12'h7C1,
|
||||
CSR_PAKEY0 = 12'h7C2,
|
||||
CSR_PAKEY1 = 12'h7C3,
|
||||
CSR_PAKEY2 = 12'h7C4,
|
||||
CSR_PAKEY3 = 12'h7C5
|
||||
} csr_num_e;
|
||||
|
||||
// CSR pmp-related offsets
|
||||
|
|
193
rtl/ibex_pointer_authentication.sv
Normal file
193
rtl/ibex_pointer_authentication.sv
Normal file
|
@ -0,0 +1,193 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
module ibex_pointer_authentication #(
|
||||
// This parameter is used in PAC instruction to rewrite MSBs of pointer to an invalid value
|
||||
parameter logic [3:0] MSBsInvalidPointer = 4'b1010
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
input logic [127:0] csr_pa_key_i,
|
||||
|
||||
input logic pac_en_i,
|
||||
input logic aut_en_i,
|
||||
input logic [31:0] pa_data0_i,
|
||||
input logic [31:0] pa_data1_i,
|
||||
|
||||
input logic pa_ready_id_i,
|
||||
|
||||
output logic [31:0] pa_result_o,
|
||||
output logic pa_valid_o
|
||||
);
|
||||
|
||||
logic [3:0] msbs_pointer_q, msbs_pointer_d;
|
||||
|
||||
// We could theoretically avoid to buffer the pac
|
||||
// by changing the decoder to provide the following outputs:
|
||||
// Cycle 1: ptr MSBs (just store ptr MSBs, ignore the pac coming from same register)
|
||||
// Cycle 2: ptr LSBs + context (now we can start the cipher)
|
||||
// Cycle 3 onwards: pac
|
||||
// But this is not currently done as it requires a lot of changes.
|
||||
logic [27:0] pac_q, pac_d;
|
||||
|
||||
logic [63:0] cipher_in_data;
|
||||
logic cipher_in_ready;
|
||||
logic cipher_in_valid;
|
||||
logic [31:0] cipher_out_data;
|
||||
logic cipher_out_ready;
|
||||
logic cipher_out_valid;
|
||||
|
||||
ibex_cipher ibex_cipher_i (
|
||||
.clk_i ( clk_i ),
|
||||
.rst_ni ( rst_ni ),
|
||||
.key_i ( csr_pa_key_i ),
|
||||
.in_data_i ( cipher_in_data ),
|
||||
.in_valid_i ( cipher_in_valid ),
|
||||
.in_ready_o ( cipher_in_ready ),
|
||||
.out_data_o ( cipher_out_data ),
|
||||
.out_valid_o ( cipher_out_valid ),
|
||||
.out_ready_i ( cipher_out_ready )
|
||||
);
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
PA_IDLE, PA_START_AUT, PA_WAIT
|
||||
} pa_fsm_e;
|
||||
pa_fsm_e pa_fsm_q, pa_fsm_d;
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
PAC_START, PAC_DONE, AUT_SUCCESS, AUT_FAILURE
|
||||
} pa_result_sel_e;
|
||||
pa_result_sel_e pa_result_sel;
|
||||
|
||||
typedef enum logic [1:0] {
|
||||
CIPHER_IDLE, CIPHER_PAC_START, CIPHER_AUT_START
|
||||
} cipher_in_data_sel_e;
|
||||
cipher_in_data_sel_e cipher_in_data_sel;
|
||||
|
||||
always_comb begin : pa_result_mux
|
||||
unique case (pa_result_sel)
|
||||
// MSBs of invalid pointer, LSBs of pointer
|
||||
PAC_START: pa_result_o = {MSBsInvalidPointer, pa_data0_i[27:0]};
|
||||
// MSBs of pointer, Pointer Authentication Code
|
||||
PAC_DONE: pa_result_o = {msbs_pointer_q, cipher_out_data[27:0]};
|
||||
// MSBs of pointer, LSB of pointer
|
||||
AUT_SUCCESS: pa_result_o = {msbs_pointer_q, pa_data0_i[27:0]};
|
||||
// We should make sure that the invalid bits get filled in the pointer
|
||||
// no matter the content of msbs_pointer_q
|
||||
// MSBs of invalid pointer, LSBs of pointer
|
||||
AUT_FAILURE: pa_result_o = {MSBsInvalidPointer, pa_data0_i[27:0]};
|
||||
// We usually take the first value from above,
|
||||
// but AUT_FAILURE seems to be more sensible in this scenario
|
||||
default: pa_result_o = {MSBsInvalidPointer, pa_data0_i[27:0]};
|
||||
endcase
|
||||
end
|
||||
|
||||
always_comb begin : cipher_in_data_mux
|
||||
unique case (cipher_in_data_sel)
|
||||
CIPHER_IDLE: cipher_in_data = '0;
|
||||
// context, MSBs of pointer, LSBs of pointer
|
||||
CIPHER_PAC_START: cipher_in_data = {pa_data1_i, msbs_pointer_d, pa_data0_i[27:0]};
|
||||
CIPHER_AUT_START: cipher_in_data = {pa_data1_i, msbs_pointer_q, pa_data0_i[27:0]};
|
||||
endcase
|
||||
end
|
||||
|
||||
// FSM
|
||||
always_comb begin
|
||||
pa_result_sel = AUT_FAILURE;
|
||||
pa_valid_o = '0;
|
||||
|
||||
msbs_pointer_d = msbs_pointer_q;
|
||||
pac_d = pac_q;
|
||||
|
||||
cipher_in_data_sel = CIPHER_IDLE;
|
||||
cipher_in_valid = '0;
|
||||
cipher_out_ready = '0;
|
||||
|
||||
pa_fsm_d = pa_fsm_q;
|
||||
|
||||
unique case (pa_fsm_q)
|
||||
|
||||
PA_IDLE: begin
|
||||
unique case (1'b1)
|
||||
pac_en_i: begin
|
||||
pa_result_sel = PAC_START;
|
||||
msbs_pointer_d = pa_data0_i[31:28];
|
||||
cipher_in_data_sel = CIPHER_PAC_START;
|
||||
cipher_in_valid = 1'b1;
|
||||
if (cipher_in_ready) begin
|
||||
pa_fsm_d = PA_WAIT;
|
||||
end
|
||||
end
|
||||
aut_en_i: begin
|
||||
msbs_pointer_d = pa_data1_i[31:28];
|
||||
pac_d = pa_data1_i[27:0];
|
||||
pa_fsm_d = PA_START_AUT;
|
||||
end
|
||||
default: begin
|
||||
pa_fsm_d = PA_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
PA_START_AUT: begin
|
||||
cipher_in_data_sel = CIPHER_AUT_START;
|
||||
cipher_in_valid = 1'b1;
|
||||
if (cipher_in_ready) begin
|
||||
pa_fsm_d = PA_WAIT;
|
||||
end
|
||||
end
|
||||
|
||||
PA_WAIT: begin
|
||||
unique case (1'b1)
|
||||
pac_en_i: begin
|
||||
if (pa_ready_id_i) begin
|
||||
cipher_out_ready = 1'b1;
|
||||
end
|
||||
if (cipher_out_ready && cipher_out_valid) begin
|
||||
pa_result_sel = PAC_DONE;
|
||||
pa_valid_o = 1'b1;
|
||||
pa_fsm_d = PA_IDLE;
|
||||
end
|
||||
end
|
||||
aut_en_i: begin
|
||||
if (pa_ready_id_i) begin
|
||||
cipher_out_ready = 1'b1;
|
||||
end
|
||||
if (cipher_out_ready && cipher_out_valid) begin
|
||||
if (pac_q == cipher_out_data[27:0]) begin // Authentication success
|
||||
pa_result_sel = AUT_SUCCESS;
|
||||
end else begin // Authentication failure
|
||||
pa_result_sel = AUT_FAILURE;
|
||||
end
|
||||
pa_valid_o = 1'b1;
|
||||
pa_fsm_d = PA_IDLE;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
pa_fsm_d = PA_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
default: begin
|
||||
pa_fsm_d = PA_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// registers for FSM
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if(~rst_ni) begin
|
||||
pa_fsm_q <= PA_IDLE;
|
||||
msbs_pointer_q <= '0;
|
||||
pac_q <= '0;
|
||||
end else begin
|
||||
pa_fsm_q <= pa_fsm_d;
|
||||
msbs_pointer_q <= msbs_pointer_d;
|
||||
pac_q <= pac_d;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Add table
Add a link
Reference in a new issue