blob: e5bb953a631f894a2ff37f1f43909e2fe3191e58 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// Sequence that probes into AES to verify that the masking can be switched off if
// these four conditions are met together:
// - The corresponding Sec parameter is enabled.
// - The force_masks configuration bit is set.
// - EDN produces the correct seed for the AES masking PRNG to output an all-zero vector.
// - Share 1 of the initial key is an all-zero vector.
class chip_sw_aes_masking_off_vseq extends chip_sw_base_vseq;
`uvm_object_utils(chip_sw_aes_masking_off_vseq)
`uvm_object_new
string aes_cipher_core_path;
int unsigned block_ctr;
int unsigned num_blocks;
function automatic bit hdl_read_bit(string path, string failure_msg);
bit val;
`DV_CHECK_FATAL(uvm_hdl_read(path, val), failure_msg)
return val;
endfunction
function automatic logic hdl_read_logic(string path);
logic val;
`DV_CHECK_FATAL(uvm_hdl_read(path, val))
return val;
endfunction
function automatic aes_pkg::sp2v_e hdl_read_sp2v(string path);
logic [aes_pkg::Sp2VWidth-1:0] val;
`DV_CHECK_FATAL(uvm_hdl_read(path, val))
return aes_pkg::sp2v_e'(val);
endfunction
function automatic logic [aes_pkg::WidthPRDMasking-1:0] hdl_read_prd(string path);
logic [aes_pkg::WidthPRDMasking-1:0] val;
`DV_CHECK_FATAL(uvm_hdl_read(path, val))
return val;
endfunction
function automatic logic [255:0] hdl_read_aes_key_share(string path);
logic [255:0] val;
`DV_CHECK_FATAL(uvm_hdl_read(path, val))
return val;
endfunction
function automatic logic [127:0] hdl_read_aes_state_share(string path);
logic [127:0] val;
`DV_CHECK_FATAL(uvm_hdl_read(path, val))
return val;
endfunction
task check_masking_prng();
string aes_masking_prng_path;
bit allow_forcing_masks;
logic force_masks;
logic reseed_req;
logic reseed_ack;
logic [aes_pkg::WidthPRDMasking-1:0] prd;
// Set path to masking PRNG.
aes_masking_prng_path =
$sformatf("%s.gen_masks.u_aes_prng_masking", aes_cipher_core_path);
// Check parameter value.
allow_forcing_masks = hdl_read_bit($sformatf("%s.SecAllowForcingMasks", aes_masking_prng_path),
"Could not read SecAllowForcingMasks parameter value.");
`DV_CHECK_EQ_FATAL(allow_forcing_masks, 1'b1,
"SecAllowForcingMasks parameter seems not to be enabled.")
// Wait for config bit to be set.
`uvm_info(`gfn, "Waiting for force_masks config bit to be set.", UVM_LOW)
`DV_SPINWAIT(
forever begin
force_masks = hdl_read_logic($sformatf("%s.force_masks_i", aes_masking_prng_path));
if (force_masks == 1'b1) break;
@(cfg.chip_vif.cpu_clk_rst_if.cbn);
end
)
// Wait for masking PRNG reseed to finish.
`uvm_info(`gfn, "Waiting for AES masking PRNG reseed to finish.", UVM_LOW)
`DV_SPINWAIT(
forever begin
reseed_req = hdl_read_logic($sformatf("%s.reseed_req_i", aes_masking_prng_path));
reseed_ack = hdl_read_logic($sformatf("%s.reseed_ack_o", aes_masking_prng_path));
@(cfg.chip_vif.cpu_clk_rst_if.cbn);
if (reseed_req == 1'b1 && reseed_ack == 1'b1) break;
end
)
// Verify that PRNG output remains zero while doing some AES encryptions.
`uvm_info(`gfn, "Verifying that AES masking PRNG outputs zero.", UVM_LOW)
while (block_ctr < num_blocks) begin
prd = hdl_read_prd($sformatf("%s.data_o", aes_masking_prng_path));
`DV_CHECK_EQ_FATAL(prd, '0, "PRNG output not equal zero.")
@(cfg.chip_vif.cpu_clk_rst_if.cbn);
end
endtask
task check_cipher_core();
bit masking;
aes_pkg::sp2v_e in_valid;
aes_pkg::sp2v_e in_ready;
aes_pkg::sp2v_e crypt;
aes_pkg::sp2v_e sub_bytes_en;
aes_pkg::sp2v_e sub_bytes_out_req;
aes_pkg::sp2v_e state_we;
aes_pkg::sp2v_e out_valid;
aes_pkg::sp2v_e out_ready;
logic [255:0] key_init_share1;
logic [127:0] state_init_share1;
logic [127:0] state_d_share1;
logic [127:0] state_o_share1;
logic [127:0] sb_in_mask;
logic [127:0] sb_out_mask;
// Check parameter value.
masking = hdl_read_bit($sformatf("%s.SecMasking", aes_cipher_core_path),
"Could not read SecMasking parameter value.");
`DV_CHECK_EQ_FATAL(masking, 1'b1,
"SecMasking parameter seems not to be enabled.")
// Wait for first encryption to start.
`uvm_info(`gfn, "Waiting for first encryption to start.", UVM_LOW)
`DV_SPINWAIT(
forever begin
in_valid = hdl_read_sp2v($sformatf("%s.in_valid_i", aes_cipher_core_path));
in_ready = hdl_read_sp2v($sformatf("%s.in_ready_o", aes_cipher_core_path));
crypt = hdl_read_sp2v($sformatf("%s.crypt_i", aes_cipher_core_path));
if (in_valid == aes_pkg::SP2V_HIGH && in_ready == aes_pkg::SP2V_HIGH &&
crypt == aes_pkg::SP2V_HIGH) break;
@(cfg.chip_vif.cpu_clk_rst_if.cbn);
end
)
// Verify that the masking is off for the next couple of encryptions.
`uvm_info(`gfn, "Verifying that AES masking is switched off.", UVM_LOW)
while (block_ctr < num_blocks) begin
// Probe handshake and control signals.
in_valid = hdl_read_sp2v($sformatf("%s.in_valid_i", aes_cipher_core_path));
in_ready = hdl_read_sp2v($sformatf("%s.in_ready_o", aes_cipher_core_path));
crypt = hdl_read_sp2v($sformatf("%s.crypt_o", aes_cipher_core_path));
sub_bytes_en = hdl_read_sp2v($sformatf("%s.sub_bytes_en", aes_cipher_core_path));
sub_bytes_out_req = hdl_read_sp2v($sformatf("%s.sub_bytes_out_req", aes_cipher_core_path));
state_we = hdl_read_sp2v($sformatf("%s.state_we", aes_cipher_core_path));
out_valid = hdl_read_sp2v($sformatf("%s.out_valid_o", aes_cipher_core_path));
out_ready = hdl_read_sp2v($sformatf("%s.out_ready_i", aes_cipher_core_path));
// Check Share 1 of the initial key and input.
if (in_valid == aes_pkg::SP2V_HIGH) begin
key_init_share1 = hdl_read_aes_key_share($sformatf("%s.key_init_i[1]",
aes_cipher_core_path));
`DV_CHECK_EQ_FATAL(key_init_share1, '0, "Share 1 of the initial key not equal zero.")
state_init_share1 = hdl_read_aes_state_share($sformatf("%s.state_init_i[1]",
aes_cipher_core_path));
`DV_CHECK_EQ_FATAL(state_init_share1, '0, "Share 1 of the input not equal zero.")
end
// Check mask input and output of SubBytes.
if (sub_bytes_en == aes_pkg::SP2V_HIGH) begin
sb_in_mask = hdl_read_aes_state_share($sformatf("%s.sb_in_mask", aes_cipher_core_path));
`DV_CHECK_EQ_FATAL(sb_in_mask, '0, "SubBytes mask input not equal zero.")
end
if (sub_bytes_out_req == aes_pkg::SP2V_HIGH) begin
sb_out_mask = hdl_read_aes_state_share($sformatf("%s.sb_out_mask", aes_cipher_core_path));
`DV_CHECK_EQ_FATAL(sb_out_mask, '0, "SubBytes mask output not equal zero.")
end
// Check Share 1 of the value written to the state register when doing an encryption unless
// we're in the last round.
if (crypt == aes_pkg::SP2V_HIGH &&
state_we == aes_pkg::SP2V_HIGH &&
out_valid != aes_pkg::SP2V_HIGH) begin
state_d_share1 = hdl_read_aes_state_share($sformatf("%s.state_d[1]",
aes_cipher_core_path));
`DV_CHECK_EQ_FATAL(state_d_share1, '0, "Share 1 of the state register not equal zero.")
end
// Check Share 1 of the output.
if (out_valid == aes_pkg::SP2V_HIGH) begin
state_o_share1 = hdl_read_aes_state_share($sformatf("%s.state_o[1]",
aes_cipher_core_path));
`DV_CHECK_EQ_FATAL(state_o_share1, '0, "Share 1 of the output not equal zero.")
end
// Advance the block counter.
if (out_valid == aes_pkg::SP2V_HIGH && out_ready == aes_pkg::SP2V_HIGH) begin
block_ctr++;
end
@(cfg.chip_vif.cpu_clk_rst_if.cbn);
end
endtask
virtual task body();
super.body();
// Set path to the AES cipher core.
aes_cipher_core_path = "tb.dut.top_earlgrey.u_aes.u_aes_core.u_aes_cipher_core";
// Initialize block counter. We will do 4 blocks.
block_ctr = 0;
num_blocks = 4;
fork
check_masking_prng();
check_cipher_core();
join
// Wait for the SW test to finish with pass/fail status.
`DV_WAIT(cfg.sw_test_status_vif.sw_test_status inside {SwTestStatusPassed, SwTestStatusFailed})
endtask
endclass