Skip to content

Commit 3da9541

Browse files
committed
[aes,dv] Test AES-GCM save and restore feature
This commit adds a directed test that checks whether AES-GCM operations can be stored and restored using the dedicated feature. Signed-off-by: Pascal Nasahl <[email protected]>
1 parent 6416650 commit 3da9541

12 files changed

+294
-12
lines changed

hw/ip/aes/data/aes_testplan.hjson

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@
103103
stage: V2
104104
tests: ["aes_nist_vectors_gcm"]
105105
}
106+
{
107+
name: gcm_save_restore
108+
desc: '''
109+
Test whether an AES-GCM operation can be saved and restored.'''
110+
stage: V2
111+
tests: ["aes_gcm_save_restore"]
112+
}
106113
{
107114
name: reset_recovery
108115
desc: '''

hw/ip/aes/dv/aes_base_sim_cfg.hjson

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@
135135
uvm_test: aes_fi_test
136136
uvm_test_seq: aes_readability_vseq
137137
}
138+
{
139+
name: aes_gcm_save_restore
140+
uvm_test: aes_gcm_save_restore_test
141+
uvm_test_seq: aes_gcm_save_restore_vseq
142+
}
138143
// Regular tests for which the scoreboard is active.
139144
{
140145
name: aes_smoke

hw/ip/aes/dv/env/aes_env.core

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ filesets:
4545
- seq_lib/aes_core_fi_vseq.sv: {is_include_file: true}
4646
- seq_lib/aes_readability_vseq.sv: {is_include_file: true}
4747
- seq_lib/aes_stress_all_vseq.sv: {is_include_file: true}
48+
- seq_lib/aes_gcm_save_restore_vseq.sv: {is_include_file: true}
4849
file_type: systemVerilogSource
4950

5051
generate:

hw/ip/aes/dv/env/aes_env_pkg.sv

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ package aes_env_pkg;
3030
parameter uint NUM_EDN = 1;
3131

3232
typedef enum int {
33-
AES_CFG = 0,
34-
AES_DATA = 1,
35-
AES_ERR_INJ = 2,
36-
AES_GCM_AAD = 3,
37-
AES_GCM_TAG = 4
33+
AES_CFG = 0,
34+
AES_DATA = 1,
35+
AES_ERR_INJ = 2,
36+
AES_GCM_AAD = 3,
37+
AES_GCM_TAG = 4,
38+
AES_GCM_SAVE = 5,
39+
AES_GCM_RESTORE = 6
3840
} aes_item_type_e;
3941

4042
typedef enum int {

hw/ip/aes/dv/env/aes_message_item.sv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ class aes_message_item extends uvm_sequence_item;
333333
if (item.mode == AES_GCM) begin
334334
if (item.item_type == AES_GCM_AAD) begin
335335
add_aad_item(item);
336-
end else begin
336+
end else if (item.item_type == AES_DATA) begin
337337
`uvm_info(`gfn, $sformatf("ADDING DATA ITEM TYPE IS %s", item.item_type.name()), UVM_LOW)
338338
add_data_item(item);
339339
end

hw/ip/aes/dv/env/aes_scoreboard.sv

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,12 @@ class aes_scoreboard extends cip_base_scoreboard #(
105105

106106
function void on_ctrl_gcm_shadowed_write(logic [31:0] wdata);
107107
case (get_field_val(ral.ctrl_gcm_shadowed.phase, wdata))
108-
GCM_INIT: input_item.item_type = AES_CFG;
109-
GCM_TEXT: input_item.item_type = AES_DATA;
110-
GCM_AAD: input_item.item_type = AES_GCM_AAD;
111-
GCM_TAG: input_item.item_type = AES_GCM_TAG;
108+
GCM_INIT: input_item.item_type = AES_CFG;
109+
GCM_TEXT: input_item.item_type = AES_DATA;
110+
GCM_AAD: input_item.item_type = AES_GCM_AAD;
111+
GCM_TAG: input_item.item_type = AES_GCM_TAG;
112+
GCM_SAVE: input_item.item_type = AES_GCM_SAVE;
113+
GCM_RESTORE: input_item.item_type = AES_GCM_RESTORE;
112114
default: input_item.item_type = AES_CFG;
113115
endcase
114116

hw/ip/aes/dv/env/seq_lib/aes_base_vseq.sv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,12 +248,12 @@ class aes_base_vseq extends cip_base_vseq #(
248248
// Write the shadwoed CTRL register.
249249
status_t status;
250250
// Setup fields one by one (0) or all fields together (1).
251-
bit setup_mode = 0;
251+
bit setup_mode = 1;
252252
// Trigger a control update error (1) or not (0). Only applicable if setup_mode = 1.
253253
bit control_update_error = 0;
254254
// Index of the field which shall trigger the control update error.
255255
int idx_error_field = 0;
256-
`DV_CHECK_STD_RANDOMIZE_FATAL(setup_mode)
256+
//`DV_CHECK_STD_RANDOMIZE_FATAL(setup_mode)
257257
if ($urandom_range(1, 100) > 95) control_update_error = 1;
258258
idx_error_field = $urandom_range(0, 5);
259259
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
// Copyright lowRISC contributors (OpenTitan project).
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
// Test processes several AES-GCM messages. During each message, at a random
6+
// item, the GCM save and restore feature is tested. Here, before the new item
7+
// is processed, the current state is saved, the registers are cleared, and the
8+
// state is restored. Then, the test continues processing the item.
9+
10+
// scoreboard is disabled for this test
11+
class aes_gcm_save_restore_vseq extends aes_base_vseq;
12+
`uvm_object_utils(aes_gcm_save_restore_vseq)
13+
14+
`uvm_object_new
15+
aes_message_item msg;
16+
bit rst_set;
17+
bit do_b2b = 0;
18+
19+
task body();
20+
`uvm_info(`gfn, $sformatf("\n\n\t ----| STARTING AES-GCM SAVE & RESTORE SEQUENCE |----\n %s",
21+
cfg.convert2string()), UVM_MEDIUM)
22+
23+
fork
24+
// Start sideload (even if not used).
25+
start_sideload_seq();
26+
join_none
27+
28+
// Generate list of messages.
29+
generate_message_queue();
30+
31+
// Process all messages.
32+
while (message_queue.size() > 0 ) begin
33+
bit new_aad = 1;
34+
bit new_data = 1;
35+
int item_cnt = 1;
36+
int save_restore_item;
37+
int crypto_res;
38+
int aad_len, data_len;
39+
bit operation;
40+
bit [3:0][31:0] predicted_tag;
41+
bit [3:0][31:0] saved_gcm_state, saved_iv;
42+
aes_seq_item cfg_item = new();
43+
aes_seq_item cfg_item_restored_iv = new();
44+
aes_seq_item data_item = new();
45+
46+
`uvm_info(`gfn, $sformatf("Starting New Message - messages left %d",
47+
message_queue.size() ), UVM_MEDIUM)
48+
49+
msg = message_queue.pop_back();
50+
aad_len = msg.aad_length;
51+
data_len = msg.message_length;
52+
generate_aes_item_queue(msg);
53+
54+
cfg_item = aes_item_queue.pop_back();
55+
msg.add_start_msg_item(cfg_item);
56+
57+
// Wait until the DUT is idle. This is required to start the configuration.
58+
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
59+
// Configure the DUT. Depending on the configuration, this might trigger a PRNG reseed
60+
// operation.
61+
csr_spinwait(.ptr(ral.status.idle) , .exp_data(1'b1));
62+
setup_dut(cfg_item);
63+
64+
// Wait until the DUT is idle. This is required to provide key and IV.
65+
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
66+
// Provide key, IV and data.
67+
write_data_key_iv(cfg_item, cfg_item, 1, cfg_item.manual_op, 0, 0, rst_set);
68+
if (cfg_item.manual_op && !rst_set) trigger();
69+
if (cfg_item.manual_op && !rst_set) trigger();
70+
71+
// At which item do we perform the save and restore?
72+
// Do not perform before we have processed the first item and also when
73+
// handling the tag.
74+
save_restore_item = 0;//$urandom_range(2, aes_item_queue.size() - 1);
75+
76+
// Process all items.
77+
while (aes_item_queue.size() > 0 ) begin
78+
int valid_bytes;
79+
// Wait until the DUT is idle.
80+
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
81+
82+
data_item = aes_item_queue.pop_back();
83+
`uvm_info(`gfn, $sformatf("\n\t ----AES ITEM %s",
84+
data_item.convert2string()), UVM_MEDIUM)
85+
86+
if (item_cnt == save_restore_item) begin
87+
`uvm_info(`gfn, $sformatf("Saving AES-GCM state before processing item %d",
88+
item_cnt), UVM_MEDIUM)
89+
set_gcm_phase(GCM_SAVE, 16, 0);
90+
if (cfg_item.manual_op) trigger();
91+
// Save the current AES-GCM context.
92+
csr_spinwait(.ptr(ral.status.output_valid), .exp_data(1'b1));
93+
read_data(saved_gcm_state, do_b2b);
94+
// Save the current IV.
95+
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
96+
read_iv(saved_iv, do_b2b);
97+
`downcast(cfg_item_restored_iv, cfg_item.clone());
98+
cfg_item_restored_iv.iv = saved_iv;
99+
cfg_item_restored_iv.iv[3] = '0; // Clear upper IV bits to restore the original IV.
100+
// Clear the AES IV, data in, and data out registers.
101+
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
102+
clear_regs(2'b11);
103+
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
104+
`uvm_info(`gfn, $sformatf("Restoring AES-GCM state before processing item %d",
105+
item_cnt), UVM_MEDIUM)
106+
// Reconfigure the initial IV and the key.
107+
write_data_key_iv(cfg_item_restored_iv, data_item, 1, cfg_item.manual_op,
108+
0, 0, rst_set);
109+
if (cfg_item.manual_op) trigger();
110+
if (cfg_item.manual_op) trigger();
111+
112+
// Restore the saved AES-GCM context.
113+
set_gcm_phase(GCM_RESTORE, 16, 1);
114+
csr_spinwait(.ptr(ral.status.input_ready), .exp_data(1'b1));
115+
add_data(saved_gcm_state, do_b2b);
116+
// Restore the saved IV.
117+
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
118+
write_iv(saved_iv, do_b2b);
119+
if (cfg_item.manual_op) trigger();
120+
`uvm_info(`gfn, $sformatf("Proceeding with item %d", item_cnt), UVM_MEDIUM)
121+
csr_spinwait(.ptr(ral.status.idle), .exp_data(1'b1));
122+
// Enforce setting the GCM phase for the next item.
123+
new_aad = 1;
124+
new_data = 1;
125+
end
126+
127+
if (data_item.item_type == AES_GCM_AAD) begin
128+
if (new_aad || data_item.data_len[3:0] != 4'd0) begin
129+
// Configure AAD phase as this is either the first AAD block or a
130+
// partial block.
131+
valid_bytes = data_item.data_len == 0 ? 16 : data_item.data_len;
132+
set_gcm_phase(GCM_AAD, valid_bytes, 0);
133+
new_aad = 0;
134+
end
135+
csr_spinwait(.ptr(ral.status.input_ready), .exp_data(1'b1));
136+
add_data(data_item.data_in, do_b2b);
137+
if (cfg_item.manual_op) trigger();
138+
// Add AAD to message.
139+
msg.add_aad_item(data_item);
140+
end else if (data_item.item_type == AES_DATA) begin
141+
if (new_data || data_item.data_len[3:0] != 4'd0) begin
142+
// Configure TEXT phase as this is either the first plaintext block or a
143+
// partial block.
144+
valid_bytes = data_item.data_len == 0 ? 16 : data_item.data_len;
145+
set_gcm_phase(GCM_TEXT, valid_bytes, 0);
146+
new_aad = 0;
147+
end
148+
csr_spinwait(.ptr(ral.status.input_ready), .exp_data(1'b1));
149+
add_data(data_item.data_in, do_b2b);
150+
if (cfg_item.manual_op) trigger();
151+
csr_spinwait(.ptr(ral.status.output_valid), .exp_data(1'b1));
152+
read_data(data_item.data_out, do_b2b);
153+
// Add input and output data block to message.
154+
msg.add_data_item(data_item);
155+
end else if (data_item.item_type == AES_GCM_TAG) begin
156+
set_gcm_phase(GCM_TAG, 16, 0);
157+
csr_spinwait(.ptr(ral.status.input_ready), .exp_data(1'b1));
158+
add_data(data_item.data_in, do_b2b);
159+
if (cfg_item.manual_op) trigger();
160+
csr_spinwait(.ptr(ral.status.output_valid), .exp_data(1'b1));
161+
read_data(data_item.data_out, do_b2b);
162+
// Add tag to message.
163+
msg.add_tag_item(data_item);
164+
end
165+
item_cnt++;
166+
end
167+
168+
// Check if we got the correct output.
169+
operation = msg.aes_operation == AES_ENC ? 1'b0 :
170+
msg.aes_operation == AES_DEC ? 1'b1 : 1'b0;
171+
msg.alloc_predicted_msg();
172+
c_dpi_aes_crypt_message(cfg.ref_model, operation, msg.aes_mode, msg.aes_iv,
173+
msg.aes_keylen, msg.aes_key[0] ^ msg.aes_key[1],
174+
data_len, aad_len, msg.input_msg,
175+
msg.input_aad, msg.output_tag, msg.predicted_msg,
176+
predicted_tag, crypto_res);
177+
178+
// Check the error code of the c_dpi library.
179+
if (crypto_res < 0) begin
180+
// The underlying c_dpi cyrpto lib returns an error code < 0 if something
181+
// is wrong.
182+
`uvm_fatal(`gfn, "c_dpi crypto lib error detected!\n")
183+
end
184+
185+
// Check output data.
186+
for (int n =0 ; n < data_len; n++) begin
187+
if ((msg.output_msg[n] != msg.predicted_msg[n]) && ~msg.output_cleared[n]) begin
188+
`uvm_fatal(`gfn, $sformatf(" output_msg[%d] (0x%x) != predicted_msg[%d] (0x%x) \n",
189+
n, msg.output_msg[n], n, msg.predicted_msg[n]))
190+
end
191+
end
192+
193+
// Check tag.
194+
if (msg.aes_operation == AES_ENC) begin
195+
`uvm_info(`gfn, $sformatf("DOING TAG CHECK"), UVM_MEDIUM)
196+
predicted_tag = aes_transpose(predicted_tag);
197+
foreach(predicted_tag[n]) begin
198+
if ((predicted_tag[n] != msg.output_tag[n]) && msg.output_tag_vld) begin
199+
`uvm_fatal(`gfn, $sformatf(" predicted_tag[%d] (0x%x) != output_tag[%d] (0x%x) \n",
200+
n, predicted_tag[n], n, msg.output_tag[n]))
201+
end
202+
end
203+
end
204+
end
205+
endtask : body
206+
endclass

hw/ip/aes/dv/env/seq_lib/aes_vseq_list.sv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@
1919
`include "aes_core_fi_vseq.sv"
2020
`include "aes_readability_vseq.sv"
2121
`include "aes_stress_all_vseq.sv"
22+
`include "aes_gcm_save_restore_vseq.sv"
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright lowRISC contributors (OpenTitan project).
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
class aes_gcm_save_restore_test extends aes_base_test;
6+
7+
`uvm_component_utils(aes_gcm_save_restore_test)
8+
`uvm_component_new
9+
10+
11+
virtual function void build_phase(uvm_phase phase);
12+
super.build_phase(phase);
13+
configure_env();
14+
endfunction
15+
16+
function void configure_env();
17+
super.configure_env();
18+
// disable scoreboard for this directed test
19+
cfg.en_scb = 0;
20+
cfg.error_types = 0; // no errors
21+
cfg.num_messages_min = 1;
22+
cfg.num_messages_max = 5;
23+
// message related knobs
24+
cfg.ecb_weight = 0;
25+
cfg.cbc_weight = 0;
26+
cfg.ctr_weight = 0;
27+
cfg.ofb_weight = 0;
28+
cfg.cfb_weight = 0;
29+
cfg.gcm_weight = 100;
30+
31+
cfg.message_len_min = 16; // one block (16bytes=128bits)
32+
cfg.message_len_max = 123; //
33+
cfg.aad_len_min = 16; //
34+
cfg.aad_len_max = 123; //
35+
cfg.manual_operation_pct = 50;
36+
cfg.use_key_mask = 0;
37+
38+
cfg.fixed_data_en = 0;
39+
cfg.fixed_key_en = 0;
40+
41+
cfg.fixed_operation_en = 0;
42+
cfg.fixed_operation = aes_pkg::AES_DEC;
43+
44+
cfg.fixed_keylen_en = 0;
45+
cfg.fixed_keylen = 3'b001;
46+
47+
cfg.fixed_iv_en = 0;
48+
cfg.fixed_aad_en = 0;
49+
50+
cfg.random_data_key_iv_order = 0;
51+
cfg.read_prob = 100;
52+
cfg.write_prob = 100;
53+
54+
`DV_CHECK_RANDOMIZE_FATAL(cfg)
55+
endfunction
56+
endclass : aes_gcm_save_restore_test

hw/ip/aes/dv/tests/aes_test.core

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ filesets:
2323
- aes_manual_config_err_test.sv: {is_include_file: true}
2424
- aes_reseed_test.sv: {is_include_file: true}
2525
- aes_fi_test.sv: {is_include_file: true}
26+
- aes_gcm_save_restore_test.sv: {is_include_file: true}
2627
file_type: systemVerilogSource
2728

2829
targets:

hw/ip/aes/dv/tests/aes_test_pkg.sv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ package aes_test_pkg;
3030
`include "aes_manual_config_err_test.sv"
3131
`include "aes_reseed_test.sv"
3232
`include "aes_fi_test.sv"
33+
`include "aes_gcm_save_restore_test.sv"
3334
endpackage

0 commit comments

Comments
 (0)