[rtl] Add Pointer Authentication

This commit is contained in:
Yuichi Sugiyama 2020-06-09 15:18:12 +09:00 committed by Pirmin Vogel
parent b1ff52dc67
commit f13ac7b8b9
13 changed files with 579 additions and 64 deletions

View file

@ -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:

View file

@ -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 ),

View file

@ -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

View file

@ -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),

View file

@ -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
View 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

View file

@ -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

View file

@ -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,

View file

@ -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 //
//////////////////////////

View file

@ -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

View file

@ -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.

View file

@ -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

View 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