test(fuzzing): adding variable coverage
Adding the capability to produce coverage of the arguments of the
SMC calls as generated by the fuzzer. The output from the FVP will
be routed to UART3 where a python flow will read the data to create
tables of each SMC call with its fields shown and values given. The
option is enabled by adding SMC_FUZZ_VARIABLE_COVERAGE=1 to the
corresponding TFTF config.
Change-Id: I2d4d310976aa2c0447efbd8ec0676bb9f8699828
Signed-off-by: Mark Dykes <mark.dykes@arm.com>
diff --git a/smc_fuzz/script/generate_var_coverage.py b/smc_fuzz/script/generate_var_coverage.py
new file mode 100755
index 0000000..2227f7a
--- /dev/null
+++ b/smc_fuzz/script/generate_var_coverage.py
@@ -0,0 +1,88 @@
+# !/usr/bin/env python
+#
+# Copyright (c) 2025 Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+
+#python3 generate_var_coverage.py -sd <smc definition file> -df <SMC data file>
+#This script generates variable coverage tables from SMC definition file and output of FVP SMC calls
+import re
+import copy
+import sys
+import argparse
+import readsmclist
+from tabulate import tabulate
+
+parser = argparse.ArgumentParser(
+ prog='generate_var_coverage.py',
+ description='Creates coverage data from SMC calls in FVP model',
+ epilog='two arguments input')
+
+parser.add_argument('-df', '--datafile',help="Data from UART output of the model .")
+parser.add_argument('-sd', '--smcdefinition',help="SMC definition file .")
+
+args = parser.parse_args()
+
+print("starting variable coverage")
+
+seq = 0
+
+readsmclist.readsmclist(args.smcdefinition,seq)
+
+arglst = readsmclist.arglst
+argnumfield = readsmclist.argnumfield
+argfieldname = readsmclist.argfieldname
+argstartbit = readsmclist.argstartbit
+argendbit = readsmclist.argendbit
+argdefval = readsmclist.argdefval
+smcname = readsmclist.smcname
+argnum = readsmclist.argnum
+argname = readsmclist.argname
+smcid = readsmclist.smcid
+
+varcovvalues = {}
+
+for sn in argfieldname:
+ varcovvalues[sn] = {}
+ for an in argfieldname[sn]:
+ for fn in argfieldname[sn][an]:
+ varcovvalues[sn][fn] = set()
+
+datafile = open(args.datafile, "r")
+data_lines = datafile.readlines()
+datafile.close()
+for dline in data_lines:
+ dl = dline.strip()
+ dinstr = re.search(r'^SMC FUZZER CALL fid:([a-fA-F0-9]+)\s+arg1:([a-fA-F0-9]+)\s+arg2:([a-fA-F0-9]+)\s+arg3:([a-fA-F0-9]+)\s+arg4:([a-fA-F0-9]+)\s+arg5:([a-fA-F0-9]+)\s+arg6:([a-fA-F0-9]+)\s+arg7:([a-fA-F0-9]+)$',dl)
+ if dinstr:
+ if dinstr.group(1) in smcid:
+ scall = smcid[dinstr.group(1)]
+ for an in argfieldname[scall]:
+ for fn in argfieldname[scall][an]:
+ if int(argnumfield[scall][an][fn]) < 8:
+ argval = dinstr.group(int(argnumfield[scall][an][fn])+1)
+ astbit = int(argstartbit[scall][an][fn])
+ aenbit = int(argendbit[scall][an][fn])
+ vval = hex((int(argval,16) >> astbit) & ((2 ** (aenbit - astbit + 1)) - 1))
+ varcovvalues[scall][fn].add(vval)
+
+for sn in varcovvalues:
+ print(sn)
+ largest = 0
+ hdrs = []
+ for fn in varcovvalues[sn]:
+ if len(varcovvalues[sn][fn]) > largest:
+ largest = len(varcovvalues[sn][fn])
+ te = [["-" for x in range(len(varcovvalues[sn]))] for x in range(largest)]
+ k = 0
+ for fn in varcovvalues[sn]:
+ i = 0
+ hdrs.append(fn)
+ for val in varcovvalues[sn][fn]:
+ te[i][k] = val
+ i = i + 1
+ k = k + 1
+ print(tabulate(te, headers=hdrs, tablefmt="grid"))
+ print()
diff --git a/smc_fuzz/script/readsmclist.py b/smc_fuzz/script/readsmclist.py
index 3bfcb6a..d351552 100755
--- a/smc_fuzz/script/readsmclist.py
+++ b/smc_fuzz/script/readsmclist.py
@@ -14,6 +14,9 @@
argstartbit = {}
argendbit = {}
argdefval = {}
+smcid = {}
+defval = {}
+sdef = {}
smcname = ""
argnum = ""
argname = ""
@@ -23,9 +26,54 @@
smclist_lines = smclistfile.readlines()
smclistfile.close()
for sline in smclist_lines:
+ svar = 0
lcon = 0
sl = sline.strip()
- sinstr = re.search(r'^smc:\s*([a-zA-Z0-9_]+)$',sl)
+ sinstr = re.search(r'^smc:\s*([a-zA-Z0-9_]+)\s*0x([a-fA-F0-9]+)\s*$',sl)
+ if sinstr:
+ smcname = sinstr.group(1)
+ arglst[sinstr.group(1)] = []
+ argnumfield[sinstr.group(1)] = {}
+ argfieldname[sinstr.group(1)] = {}
+ argstartbit[sinstr.group(1)] = {}
+ argendbit[sinstr.group(1)] = {}
+ argdefval[sinstr.group(1)] = {}
+ smcid[sinstr.group(2)] = sinstr.group(1)
+ svar = 1
+ lcon = 1
+ argoccupy = {}
+ if not seq:
+ seq = seq + 1
+ else:
+ if seq != 2:
+ print("Error: out of sequence for smc call",end=" ")
+ print(smcname)
+ sys.exit()
+ else:
+ seq = 1
+ sinstr = re.search(r'^smc:\s*([a-zA-Z0-9_]+)\s*([a-zA-Z0-9_]+)\s*$',sl)
+ if sinstr and (svar == 0):
+ smcname = sinstr.group(1)
+ arglst[sinstr.group(1)] = []
+ argnumfield[sinstr.group(1)] = {}
+ argfieldname[sinstr.group(1)] = {}
+ argstartbit[sinstr.group(1)] = {}
+ argendbit[sinstr.group(1)] = {}
+ argdefval[sinstr.group(1)] = {}
+ sdef[sinstr.group(1)] = sinstr.group(2)
+ smcid[sinstr.group(2)] = sinstr.group(1)
+ lcon = 1
+ argoccupy = {}
+ if not seq:
+ seq = seq + 1
+ else:
+ if seq != 2:
+ print("Error: out of sequence for smc call",end=" ")
+ print(smcname)
+ sys.exit()
+ else:
+ seq = 1
+ sinstr = re.search(r'^smc:\s*([a-zA-Z0-9_]+)\s*$',sl)
if sinstr:
smcname = sinstr.group(1)
arglst[sinstr.group(1)] = []
@@ -181,6 +229,10 @@
if seq != 2:
print("Error: out of sequence for field")
sys.exit()
+ sinstr = re.search(r'^define ([a-zA-Z0-9_]+)\s*=\s*0x([a-fA-F0-9]+|\d+)$',sl)
+ if sinstr:
+ defval[sinstr.group(1)] = sinstr.group(2)
+ lcon = 1
if not lcon:
cline = re.search(r'^#',sl)
if not cline:
@@ -191,3 +243,11 @@
if(seq != 2):
print("incorrect ending for smc specification")
sys.exit()
+
+ for smccal,dval in sdef.items():
+ if dval in defval:
+ smcid[defval[dval]] = smccal
+ else:
+ print("Error: cannot find define value",end=" ")
+ print(dval)
+ sys.exit()
diff --git a/smc_fuzz/sdei_smc_calls.txt b/smc_fuzz/sdei_smc_calls.txt
index 3017630..ccf8992 100644
--- a/smc_fuzz/sdei_smc_calls.txt
+++ b/smc_fuzz/sdei_smc_calls.txt
@@ -4,15 +4,35 @@
# SPDX-License-Identifier: BSD-3-Clause
#
-smc: SDEI_EVENT_STATUS_CALL
+define SDEI_EVENT_STATUS_CALL_SMCID = 0xc4000028
+define SDEI_INTERRUPT_BIND_CALL_SMCID = 0xc400002d
+define SDEI_VERSION_CALL_SMCID = 0xc4000020
+define SDEI_EVENT_REGISTER_CALL_SMCID = 0xc4000021
+define SDEI_EVENT_ENABLE_CALL_SMCID = 0xc4000022
+define SDEI_FEATURES_CALL_SMCID = 0xc4000030
+define SDEI_EVENT_DISABLE_CALL_SMCID = 0xc4000023
+define SDEI_EVENT_CONTEXT_CALL_SMCID = 0xc4000024
+define SDEI_EVENT_COMPLETE_CALL_SMCID = 0xc4000025
+define SDEI_EVENT_COMPLETE_AND_RESUME_CALL_SMCID = 0xc4000026
+define SDEI_EVENT_UNREGISTER_CALL_SMCID = 0xc4000027
+define SDEI_EVENT_GET_INFO_CALL_SMCID = 0xc4000029
+define SDEI_EVENT_ROUTING_SET_CALL_SMCID = 0xc400002a
+define SDEI_PE_MASK_CALL_SMCID = 0xc400002b
+define SDEI_PE_UNMASK_CALL_SMCID = 0xc400002c
+define SDEI_INTERRUPT_RELEASE_CALL_SMCID = 0xc400002e
+define SDEI_EVENT_SIGNAL_CALL_SMCID = 0xc400002f
+define SDEI_PRIVATE_RESET_CALL_SMCID = 0xc4000031
+define SDEI_SHARED_RESET_CALL_SMCID = 0xc4000032
+
+smc: SDEI_EVENT_STATUS_CALL SDEI_EVENT_STATUS_CALL_SMCID
arg1:bev
field:bev:[0,31] = 0
-smc: SDEI_INTERRUPT_BIND_CALL
+smc: SDEI_INTERRUPT_BIND_CALL SDEI_INTERRUPT_BIND_CALL_SMCID
arg1:interruptnum
field:inum:[0,31] = 1
-smc: SDEI_VERSION_CALL
+smc: SDEI_VERSION_CALL SDEI_VERSION_CALL_SMCID
arg1-arg17 = 0
-smc: SDEI_EVENT_REGISTER_CALL
+smc: SDEI_EVENT_REGISTER_CALL SDEI_EVENT_REGISTER_CALL_SMCID
arg1:eventnum
field:enum:[0,31] = 0
arg2:entryaddr
@@ -25,33 +45,33 @@
field:reserved:[2,63] = 0
arg5:affinity
field:aff:[0,63] = 0
-smc: SDEI_EVENT_ENABLE_CALL
+smc: SDEI_EVENT_ENABLE_CALL SDEI_EVENT_ENABLE_CALL_SMCID
arg1:eventnum
field:enum:[0,31] = 0
-smc: SDEI_FEATURES_CALL
+smc: SDEI_FEATURES_CALL SDEI_FEATURES_CALL_SMCID
arg1:feature
field:feat:[0,31] = 0
-smc: SDEI_EVENT_DISABLE_CALL
+smc: SDEI_EVENT_DISABLE_CALL SDEI_EVENT_DISABLE_CALL_SMCID
arg1:eventnum
field:enum:[0,31] = 0
-smc: SDEI_EVENT_CONTEXT_CALL
+smc: SDEI_EVENT_CONTEXT_CALL SDEI_EVENT_CONTEXT_CALL_SMCID
arg1:paramid
field:param:[0,31] = 0
-smc: SDEI_EVENT_COMPLETE_CALL
+smc: SDEI_EVENT_COMPLETE_CALL SDEI_EVENT_COMPLETE_CALL_SMCID
arg1:status
field:stat:[0,31] = 0
-smc: SDEI_EVENT_COMPLETE_AND_RESUME_CALL
+smc: SDEI_EVENT_COMPLETE_AND_RESUME_CALL SDEI_EVENT_COMPLETE_AND_RESUME_CALL_SMCID
arg1:resumeaddr
field:addr:[0,63] = 0
-smc: SDEI_EVENT_UNREGISTER_CALL
+smc: SDEI_EVENT_UNREGISTER_CALL SDEI_EVENT_UNREGISTER_CALL_SMCID
arg1:event
field:enum:[0,31] = 0
-smc: SDEI_EVENT_GET_INFO_CALL
+smc: SDEI_EVENT_GET_INFO_CALL SDEI_EVENT_GET_INFO_CALL_SMCID
arg1:event
field:enum:[0,31] = 0
arg2:info
field:info:[0,31] = 0
-smc: SDEI_EVENT_ROUTING_SET_CALL
+smc: SDEI_EVENT_ROUTING_SET_CALL SDEI_EVENT_ROUTING_SET_CALL_SMCID
arg1:event
field:enum:[0,31] = 0
arg2:routingmode
@@ -59,19 +79,19 @@
field:constant:[1,63] = 0
arg3:affinity
field:aff:[0,63] = 0
-smc: SDEI_PE_MASK_CALL
+smc: SDEI_PE_MASK_CALL SDEI_PE_MASK_CALL_SMCID
arg1 = 0
-smc: SDEI_PE_UNMASK_CALL
+smc: SDEI_PE_UNMASK_CALL SDEI_PE_UNMASK_CALL_SMCID
arg1 = 0
-smc: SDEI_INTERRUPT_RELEASE_CALL
+smc: SDEI_INTERRUPT_RELEASE_CALL SDEI_INTERRUPT_RELEASE_CALL_SMCID
arg1:event
field:enum:[0,31] = 0
-smc: SDEI_EVENT_SIGNAL_CALL
+smc: SDEI_EVENT_SIGNAL_CALL SDEI_EVENT_SIGNAL_CALL_SMCID
arg1:event
field:enum:[0,31] = 0
arg2:targetpe
field:pe:[0,31] = 0
-smc: SDEI_PRIVATE_RESET_CALL
+smc: SDEI_PRIVATE_RESET_CALL SDEI_PRIVATE_RESET_CALL_SMCID
arg1 = 0
-smc: SDEI_SHARED_RESET_CALL
+smc: SDEI_SHARED_RESET_CALL SDEI_SHARED_RESET_CALL_SMCID
arg1 = 0