Skip to content

Commit fcebf8b

Browse files
committed
[test] Add otp fi test and host scripts
Add the host scripts and the tests for the otp fi. Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent 0bb71c0 commit fcebf8b

4 files changed

Lines changed: 346 additions & 1 deletion

File tree

test/penetrationtests/fi/BUILD

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,46 @@ py_binary(
123123
}),
124124
)
125125

126+
py_binary(
127+
name = "fi_otp_test",
128+
srcs = ["test_scripts/fi_otp_test.py"],
129+
testonly = True,
130+
deps = [
131+
":fi_otp_functions",
132+
"//communication:dut",
133+
"//communication:chip",
134+
"//communication:fi_otp_commands",
135+
"//test/penetrationtests/util:utils",
136+
"@rules_python//python/runfiles",
137+
],
138+
data = [
139+
"@lowrisc_opentitan//sw/host/opentitantool",
140+
] +
141+
select({
142+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_silicon_owner_gb_rom_ext": [
143+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_fi_silicon_owner_gb_rom_ext",
144+
],
145+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_fpga_cw310_rom_with_fake_keys": [
146+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_fi_fpga_cw310_rom_with_fake_keys",
147+
],
148+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_fpga_cw310_sival_rom_ext": [
149+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_fi_fpga_cw310_sival_rom_ext",
150+
],
151+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_fpga_cw310_test_rom": [
152+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_fi_fpga_cw310_test_rom",
153+
],
154+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_silicon_owner_a2_rom_ext": [
155+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_fi_silicon_owner_a2_rom_ext",
156+
],
157+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/config:env_silicon_owner_sival_rom_ext": [
158+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_fi_silicon_owner_sival_rom_ext",
159+
],
160+
"//conditions:default": [
161+
"@lowrisc_opentitan//sw/device/tests/penetrationtests/firmware:pen_test_fi_silicon_owner_gb_rom_ext",
162+
],
163+
}),
164+
)
165+
126166
py_library(
127167
name = "fi_ibex_functions",
128168
srcs = ["host_scripts/fi_ibex_functions.py"],
@@ -151,4 +191,14 @@ py_library(
151191
"//communication:chip",
152192
"//communication:fi_otbn_commands",
153193
],
194+
)
195+
196+
py_library(
197+
name = "fi_otp_functions",
198+
srcs = ["host_scripts/fi_otp_functions.py"],
199+
deps = [
200+
"//communication:dut",
201+
"//communication:chip",
202+
"//communication:fi_otp_commands",
203+
],
154204
)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from communication.fi_otp_commands import OTFIOtp
2+
from communication.chip import *
3+
from communication.dut import DUT
4+
import time
5+
6+
def char_vendor_test(opentitantool, iterations):
7+
target = DUT()
8+
reset_target(opentitantool)
9+
# Clear the output from the reset
10+
target.dump_all()
11+
12+
otpfi = OTFIOtp(target)
13+
# Initialize our chip and catch its output
14+
device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = otpfi.init()
15+
for _ in range(iterations):
16+
otpfi.otp_fi_vendor_test()
17+
response = target.read_response()
18+
return response
19+
20+
def char_owner_sw_cfg(opentitantool, iterations):
21+
target = DUT()
22+
reset_target(opentitantool)
23+
# Clear the output from the reset
24+
target.dump_all()
25+
26+
otpfi = OTFIOtp(target)
27+
# Initialize our chip and catch its output
28+
device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = otpfi.init()
29+
for _ in range(iterations):
30+
otpfi.otp_fi_owner_sw_cfg()
31+
response = target.read_response()
32+
return response
33+
34+
def char_hw_cfg(opentitantool, iterations):
35+
target = DUT()
36+
reset_target(opentitantool)
37+
# Clear the output from the reset
38+
target.dump_all()
39+
40+
otpfi = OTFIOtp(target)
41+
# Initialize our chip and catch its output
42+
device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = otpfi.init()
43+
for _ in range(iterations):
44+
otpfi.otp_fi_hw_cfg()
45+
response = target.read_response()
46+
return response
47+
48+
def char_life_cycle(opentitantool, iterations):
49+
target = DUT()
50+
reset_target(opentitantool)
51+
# Clear the output from the reset
52+
target.dump_all()
53+
54+
otpfi = OTFIOtp(target)
55+
# Initialize our chip and catch its output
56+
device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = otpfi.init()
57+
for _ in range(iterations):
58+
otpfi.otp_fi_life_cycle()
59+
response = target.read_response()
60+
return response

test/penetrationtests/fi/test_scripts/fi_ibex_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ def main():
852852
print("Init test failure")
853853
return False
854854

855-
iterations = 2
855+
iterations = 10
856856

857857
char_addi_single_beq_test(opentitantool_path, iterations)
858858
char_addi_single_bne_test(opentitantool_path, iterations)
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
from test.penetrationtests.fi.host_scripts.fi_otp_functions import *
2+
from communication.fi_otp_commands import OTFIOtp
3+
from python.runfiles import Runfiles
4+
from communication.chip import *
5+
from test.penetrationtests.util.utils import *
6+
import os
7+
import json
8+
9+
ignored_keys_set = set(["partition_ref", "partition_fi"])
10+
11+
def reset_test(opentitantool, target):
12+
reset_target(opentitantool)
13+
while True:
14+
read_line = str(target.readline().decode().strip())
15+
if len(read_line) > 0:
16+
if "firmware_fi.c" in read_line:
17+
return True
18+
else:
19+
return False
20+
21+
22+
def init_test(opentitantool, target):
23+
otpfi = OTFIOtp(target)
24+
device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = otpfi.init()
25+
device_id_json = json.loads(device_id)
26+
sensors_json = json.loads(sensors)
27+
alerts_json = json.loads(alerts)
28+
owner_page_json = json.loads(owner_page)
29+
boot_log_json = json.loads(boot_log)
30+
boot_measurements_json = json.loads(boot_measurements)
31+
32+
expected_device_id_keys = {
33+
"device_id",
34+
"rom_digest",
35+
"icache_en",
36+
"dummy_instr_en",
37+
"clock_jitter_locked",
38+
"clock_jitter_en",
39+
"sram_main_readback_locked",
40+
"sram_main_readback_en",
41+
"sram_ret_readback_locked",
42+
"sram_ret_readback_en"
43+
}
44+
actual_device_id_keys = set(device_id_json.keys())
45+
46+
if not actual_device_id_keys == expected_device_id_keys:
47+
print("device_id keys do not match the expected set.")
48+
print(f"Expected: {expected_device_id_keys}")
49+
print(f"Actual: {actual_device_id_keys}")
50+
return False
51+
52+
expected_sensors_keys = {
53+
"sensor_ctrl_en",
54+
"sensor_ctrl_fatal"
55+
}
56+
actual_sensors_keys = set(sensors_json.keys())
57+
58+
if not expected_sensors_keys == actual_sensors_keys:
59+
print("sensor keys do not match the expected set.")
60+
print(f"Expected: {expected_sensors_keys}")
61+
print(f"Actual: {actual_sensors_keys}")
62+
return False
63+
64+
expected_alerts_keys = {
65+
"alert_classes",
66+
"enabled_alerts",
67+
"enabled_classes",
68+
"accumulation_thresholds",
69+
"duration_cycles",
70+
"escalation_signals_en",
71+
"escalation_signals_map"
72+
}
73+
actual_alerts_keys = set(alerts_json.keys())
74+
if not expected_alerts_keys == actual_alerts_keys:
75+
print("alert keys do not match the expected set.")
76+
print(f"Expected: {expected_alerts_keys}")
77+
print(f"Actual: {actual_alerts_keys}")
78+
return False
79+
80+
expected_owner_page_keys = {
81+
"config_version",
82+
"sram_exec_mode",
83+
"ownership_key_alg",
84+
"update_mode",
85+
"min_security_version_bl0",
86+
"lock_constraint"
87+
}
88+
actual_owner_page_keys = set(owner_page_json.keys())
89+
if not expected_owner_page_keys == actual_owner_page_keys:
90+
print("owner_page keys do not match the expected set.")
91+
print(f"Expected: {expected_owner_page_keys}")
92+
print(f"Actual: {actual_owner_page_keys}")
93+
return False
94+
95+
expected_boot_log_keys = {
96+
"digest",
97+
"identifier",
98+
"scm_revision_low",
99+
"scm_revision_high",
100+
"rom_ext_slot",
101+
"rom_ext_major",
102+
"rom_ext_minor",
103+
"rom_ext_size",
104+
"bl0_slot",
105+
"ownership_state",
106+
"ownership_transfers",
107+
"rom_ext_min_sec_ver",
108+
"bl0_min_sec_ver",
109+
"primary_bl0_slot",
110+
"retention_ram_initialized"
111+
}
112+
actual_boot_log_keys = set(boot_log_json.keys())
113+
if not expected_boot_log_keys == actual_boot_log_keys:
114+
print("boot_log keys do not match the expected set.")
115+
print(f"Expected: {expected_boot_log_keys}")
116+
print(f"Actual: {actual_boot_log_keys}")
117+
return False
118+
119+
expected_boot_measurements_keys = {
120+
"bl0",
121+
"rom_ext"
122+
}
123+
actual_boot_measurements_keys = set(boot_measurements_json.keys())
124+
if not expected_boot_measurements_keys == actual_boot_measurements_keys:
125+
print("boot_measurements keys do not match the expected set.")
126+
print(f"Expected: {expected_boot_measurements_keys}")
127+
print(f"Actual: {actual_boot_measurements_keys}")
128+
return False
129+
130+
if "PENTEST" not in version:
131+
print("Did not receive a PENTEST version.")
132+
print(f"Actual: {version}")
133+
return False
134+
135+
return True
136+
137+
def char_vendor_test_test(opentitantool_path, iterations):
138+
actual_result = char_vendor_test(opentitantool_path, iterations)
139+
try:
140+
actual_result_json = json.loads(actual_result)
141+
except:
142+
print("char_vendor_test gave an unexpected result")
143+
print(f"Actual: {actual_result}")
144+
return False
145+
expected_result_json = json.loads('{"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false],"otp_error_causes":[0,0,0,0,0,0,0,0,0,0],"otp_status_codes":0,"err_status":0,"alerts":[0,0,0],"ast_alerts":[0,0]}')
146+
if not compare_json_data(actual_result_json, expected_result_json, ignored_keys_set):
147+
print("char_vendor_test failed")
148+
print(f"Expected: {expected_result_json}")
149+
print(f"Actual: {actual_result_json}")
150+
print("")
151+
return False
152+
return True
153+
154+
def char_owner_sw_cfg_test(opentitantool_path, iterations):
155+
actual_result = char_owner_sw_cfg(opentitantool_path, iterations)
156+
try:
157+
actual_result_json = json.loads(actual_result)
158+
except:
159+
print("char_owner_sw_cfg gave an unexpected result")
160+
print(f"Actual: {actual_result}")
161+
return False
162+
expected_result_json = json.loads('{"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false],"otp_error_causes":[0,0,0,0,0,0,0,0,0,0],"otp_status_codes":0,"err_status":0,"alerts":[0,0,0],"ast_alerts":[0,0]}')
163+
if not compare_json_data(actual_result_json, expected_result_json, ignored_keys_set):
164+
print("char_owner_sw_cfg failed")
165+
print(f"Expected: {expected_result_json}")
166+
print(f"Actual: {actual_result_json}")
167+
print("")
168+
return False
169+
return True
170+
171+
def char_hw_cfg_test(opentitantool_path, iterations):
172+
actual_result = char_hw_cfg(opentitantool_path, iterations)
173+
try:
174+
actual_result_json = json.loads(actual_result)
175+
except:
176+
print("char_hw_cfg gave an unexpected result")
177+
print(f"Actual: {actual_result}")
178+
return False
179+
expected_result_json = json.loads('{"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false],"otp_error_causes":[0,0,0,0,0,0,0,0,0,0],"otp_status_codes":0,"err_status":0,"alerts":[0,0,0],"ast_alerts":[0,0]}')
180+
if not compare_json_data(actual_result_json, expected_result_json, ignored_keys_set):
181+
print("char_hw_cfg failed")
182+
print(f"Expected: {expected_result_json}")
183+
print(f"Actual: {actual_result_json}")
184+
print("")
185+
return False
186+
return True
187+
188+
def char_life_cycle_test(opentitantool_path, iterations):
189+
actual_result = char_life_cycle(opentitantool_path, iterations)
190+
try:
191+
actual_result_json = json.loads(actual_result)
192+
except:
193+
print("char_life_cycle gave an unexpected result")
194+
print(f"Actual: {actual_result}")
195+
return False
196+
expected_result_json = json.loads('{"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false],"otp_error_causes":[0,0,0,0,0,0,0,0,0,0],"otp_status_codes":0,"err_status":0,"alerts":[0,0,0],"ast_alerts":[0,0]}')
197+
if not compare_json_data(actual_result_json, expected_result_json, ignored_keys_set):
198+
print("char_life_cycle failed")
199+
print(f"Expected: {expected_result_json}")
200+
print(f"Actual: {actual_result_json}")
201+
print("")
202+
return False
203+
return True
204+
205+
def main():
206+
r = Runfiles.Create()
207+
opentitantool_path = r.Rlocation("lowrisc_opentitan/sw/host/opentitantool/opentitantool")
208+
209+
firmware_target_name = os.environ.get("SELECTED_FIRMWARE_TARGET", "pen_test_fi_silicon_owner_gb_rom_ext")
210+
firmware_path = r.Rlocation(f"lowrisc_opentitan/sw/device/tests/penetrationtests/firmware/{firmware_target_name}.img")
211+
212+
target = DUT()
213+
214+
flash_target(opentitantool_path, firmware_path)
215+
target.dump_all()
216+
217+
if not reset_test(opentitantool_path, target):
218+
print("Reset test failure")
219+
return False
220+
221+
if not init_test(opentitantool_path, target):
222+
print("Init test failure")
223+
return False
224+
225+
iterations = 10
226+
char_vendor_test_test(opentitantool_path, iterations)
227+
char_owner_sw_cfg_test(opentitantool_path, iterations)
228+
char_hw_cfg_test(opentitantool_path, iterations)
229+
char_life_cycle_test(opentitantool_path, iterations)
230+
231+
print("Testing finished")
232+
return True
233+
234+
if __name__ == "__main__":
235+
main()

0 commit comments

Comments
 (0)