Skip to content

Commit

Permalink
add a case-gen script for tdx-compliance-tests.
Browse files Browse the repository at this point in the history
Signed-off-by: DCyan_Elite <[email protected]>
  • Loading branch information
CrescentLove committed Oct 26, 2023
1 parent c96cd27 commit 1781a4b
Show file tree
Hide file tree
Showing 3 changed files with 278 additions and 0 deletions.
249 changes: 249 additions & 0 deletions tdx-compliance/auto_gen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@


# related filepath
import csv
import sys
import re
import pandas
import math
import json

# some parse func
def parse_leaf(field_name):
match_leaves = re.search(r'Leaf (\w+)', field_name)
match_subleafs = re.search(r'Sub-Leaves (\w+-\w+)', field_name)
match_subleaf = re.search(r'Sub-Leaf (\w+)', field_name)

if match_leaves:
leaf = match_leaves.group(1)
else:
return None, None

if match_subleafs:
subleaves_range = match_subleafs.group(1).split('-')
subleaves = [str(hex(i)) for i in range(int(subleaves_range[0], 16), int(subleaves_range[1], 16) + 1)]
elif match_subleaf:
subleaves = [match_subleaf.group(1)]
else:
subleaves = ["0x0"]

return leaf, subleaves

def get_valstr(str_wait, column_indices):
virt = None
for v in str_wait:
if v in column_indices:
virt = v
break
return virt

class GenCase:
def __init__(self, config_path):
self.config_path = config_path
self.ptype = ""
self.csv_path = ""
self.header_path = ""
self.bias = "0"
self.version = "1.0"
self.ans = []
self.body = []
self.config = {}

def read_config(self):
try:
with open(self.config_path, 'r') as config_file:
origin_data = json.load(config_file)
self.config = origin_data.get(self.ptype, {})
self.csv_path = self.config.get("csv_path", None)
self.header_path = self.config.get("header_path", None)
self.bias = self.config.get("bias", "0")
self.version = self.config.get("version", "1.0")
except Exception as e:
raise Exception(f"Failed to parse config: {e}")

def read_spec(self):
try:
df = pandas.read_csv(self.csv_path, skiprows=range(int(self.bias)))
columns = df.columns.tolist()
column_indices = {column: index for index, column in enumerate(columns)}
return df, columns, column_indices
except Exception as e:
raise Exception(f"Failed to get csv_index: {e}")

def write2header(self, funcName="initial_cpuid"):
function_name = f"void {funcName}(void)"
try:
with open(self.header_path, 'w') as header_file:
header_file.write(f"#define AUTOGEN_{self.ptype.upper()}\n")
for line in self.body:
header_file.write(line + '\n')
except Exception as e:
raise Exception(f"Failed to write to header file: {e}")

class CpuidCase(GenCase):
def __init__(self, config_path):
super().__init__(config_path)
self.ptype = "cpuid"

# 定义cpuid独属的csv的目录项
self.vDetail = ""
self.vType = ""
self.fName = ""
try:
self.read_config()
self.init_param()
except Exception as e:
print(f"Failed to initialize GenCase: {e}")
raise

def init_param(self):
self.vDetail = self.config.get("vdetail", [])
self.vType = self.config.get("vtype", [])
self.fName = self.config.get("fname", "")

def parse_csv(self):
self.ans = []
df, columns, column_indices = self.read_spec()
self.vType = get_valstr(self.vType, column_indices)
self.vDetail = get_valstr(self.vDetail, column_indices)

leaf = ""
subleaf = []
isNew = ""
for index, row in df.iterrows():
field_name = row[columns[column_indices[self.fName]]]
virt_type = row[columns[column_indices[self.vType]]]
virt_detail = str(row[columns[column_indices[self.vDetail]]])
reg = row[columns[column_indices['Reg.']]]

if isinstance(reg, float) and math.isnan(reg):
leaf, subleaf = parse_leaf(field_name)
isNew = field_name
elif virt_type == 'Fixed':
msb = int(row[columns[column_indices['MSB']]])
lsb = int(row[columns[column_indices['LSB']]])
field_size = int(row[columns[column_indices['Field Size']]])

if isNew != "":
self.ans.append([-1,-1,-1,-1,-1,-1,isNew,-1])
isNew = ""
entry = []
""" archived, replaced by parse_leaf
leaf = row[columns[column_indices['Leaf']]]
sl_from = row[columns[column_indices['Sub-Leaf From']]]
sl_to = row[columns[column_indices['Sub-Leaf To']]]
if isinstance(sl_from, float) and math.isnan(sl_from):
sl_from = 0x0
sl_to = 0x0
else:
sl_from = int(sl_from, 16)
sl_to = int(sl_to, 16)
"""
for i in subleaf:
entry = [leaf, i, reg, msb, lsb, field_size, field_name, virt_detail]
self.ans.append(entry)

def get_body(self):
self.body = []
self.body.append("void initial_cpuid(void) {")
for entry in self.ans:
leaf = entry[0]
subleaf = entry[1]
reg = entry[2]
msb = entry[3]
lsb = entry[4]
size = entry[5]
name = entry[6]
val = entry[7]
if entry[5] == -1:
self.body.append("\n\t// %s" % (name))
elif entry[5] == 32:
self.body.append("\tEXP_CPUID_BYTE(%s, %s, %s, %s, %s);\t//%s" % ( \
leaf, subleaf, reg, val, self.version, name))

elif entry[5] == 1:
self.body.append("\tEXP_CPUID_BIT(%s, %s, %s, %s, %s, %s);\t//%s" % ( \
leaf, subleaf, reg, msb, val, self.version, name))
else:
self.body.append("\tEXP_CPUID_RES_BITS(%s, %s, %s, %s, %s, %s);\t//%s" % ( \
leaf, subleaf, reg, lsb, msb, self.version, name))
self.body.append("}")

class MsrCase(GenCase):
def __init__(self, config_path):
super().__init__(config_path)
self.ptype = "msr"

# 定义msr独属的csv的目录项
self.vDetail = ""
self.rdName = ""
self.wrName = ""
try:
self.read_config()
self.init_param()
except Exception as e:
print(f"Failed to initialize GenCase: {e}")
raise

def init_param(self):
self.vDetail = self.config.get("vdetail", [])
self.rdName = self.config.get("rdnmae", [])
self.wrName = self.config.get("wrname", [])

def parse_csv(self):
self.ans = []
df, columns, column_indices = self.read_spec()
self.rdName = get_valstr(self.rdName, column_indices)
self.wrName = get_valstr(self.rdName, column_indices)

for index, row in df.iterrows():
rd_ept = row[columns[column_indices[self.rdName]]]
wr_ept = row[columns[column_indices[self.wrName]]]
virt_detail = str(row[columns[column_indices[self.vDetail]]])




def write2header(path, list, ptype, funcName="initial_cpuid"):
"""
gen a header file
:param path:
:param list: stores the generated statements for all cases.
:param funcName: the initial-func name defined in header file.
:return: if -1 is returned, it means the write failed
"""
function_name = f"void {funcName}(void)"
ptype = ptype.upper()
try:
with open(path, 'w') as header_file:
header_file.write(f"#define AUTOGEN_{ptype}\n\n")
header_file.write(f"{function_name} {{\n")

for line in list:
header_file.write('\t' + line + '\n')
header_file.write("}\n")
return 0
except:
return -1

if __name__ == '__main__':

# init all params
config_path = 'config.json'
cpuid_case = CpuidCase(config_path)
cpuid_case.parse_csv()

if not cpuid_case.ans:
print("Failed to parse csv. Exiting program.")
sys.exit(1)
#assert get_csv.ans, "ans is empty. Exiting program."
cpuid_case.get_body()

#gen a header file
cpuid_case.write2header()






25 changes: 25 additions & 0 deletions tdx-compliance/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"cpuid":{
"csv_path": "hh1_0.csv",
"header_path": "cpuid_case.h",
"vdetail": ["Virtualization Details"],
"vtype": ["Bit or Field Virtualization Type", "Virtualization Type"],
"fname": "Field Name",
"bias": "1",
"version": "1.0"
},
"cr":{
"csv_path": "",
"header_path": "",
"vdetail": "",
"vtype": "",
"bias": "2"
},
"msr":{
"csv_path": "",
"header_path": "msr_case.h",
"vdetail": "",
"vtype": "",
"bias": "2"
}
}
4 changes: 4 additions & 0 deletions tdx-compliance/tdx-compliance-cpuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
list_add_tail(&t->list, &cpuid_list); \
} while (0)

#ifdef AUTOGEN_CPUID
extern void initial_cpuid(void);
#else
void initial_cpuid(void)
{
/* CPUID(0x0) */
Expand Down Expand Up @@ -540,3 +543,4 @@ void initial_cpuid(void)
/* CPUID(0x80000008).EDX */
EXP_CPUID_RES_BITS(0x80000008, 0x0, edx, 0, 31, VER1_0); //Reserved
}
#endif

0 comments on commit 1781a4b

Please sign in to comment.