1556 lines
79 KiB
Python
1556 lines
79 KiB
Python
# @file
|
|
# Setup files parser
|
|
#
|
|
# @copyright
|
|
# INTEL CONFIDENTIAL
|
|
#
|
|
# Copyright (c) 2021 Intel Corporation. All rights reserved
|
|
# This software and associated documentation (if any) is furnished
|
|
# under a license and may only be used or copied in accordance
|
|
# with the terms of the license. Except as permitted by the
|
|
# license, no part of this software or documentation may be
|
|
# reproduced, stored in a retrieval system, or transmitted in any
|
|
# form or by any means without the express written consent of
|
|
# Intel Corporation.
|
|
# This file contains an 'Sample Driver' and is uniquely
|
|
# identified as \"Intel Reference Module\" and is licensed for Intel
|
|
# CPUs and chipsets under the terms of your license agreement with
|
|
# Intel or your vendor. This file may be modified by the user, subject
|
|
# to additional terms of the license agreement.
|
|
#
|
|
# @par Specification Reference:
|
|
from __future__ import division
|
|
from __future__ import nested_scopes
|
|
from __future__ import with_statement
|
|
from __future__ import print_function
|
|
|
|
|
|
__version__ = "1.0.0"
|
|
__author__ = ["ashinde", "gsaraiya"]
|
|
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
import glob
|
|
import copy
|
|
import time
|
|
import shutil
|
|
import string
|
|
import binascii
|
|
import argparse
|
|
import subprocess
|
|
from collections import namedtuple
|
|
|
|
|
|
PY2 = bool(sys.version_info.major == 2)
|
|
|
|
BIOS_KNOBS_DATA_BIN_HDR_SIZE = 0x50
|
|
# Version 0x4 Supports BitWise Setup Knobs
|
|
BIOS_KNOB_BIN_REVISION = 0x04 # Version 0.4
|
|
BIOS_KNOB_BIN_REVISION_HEX = hex(BIOS_KNOB_BIN_REVISION)[2:].strip().strip('L').zfill(2)
|
|
NVAR_NAME_OFFSET_IN_HDR = 0x22
|
|
NVAR_NAME_OFFSET_IN_HDR_HEX = hex(NVAR_NAME_OFFSET_IN_HDR)[2:].strip().strip('L').zfill(2)
|
|
NVAR_GUID_OFFSET_IN_HDR = 0x12
|
|
NVAR_BIT_KNOB_COUNT_OFFSET_IN_HDR = 0x4E
|
|
BIOS_KNOB_BIN_NVAR_NAME_RESERVED = 0x2C
|
|
INVERT_DICT = {'_EQU_': '_NEQ_', '_NEQ_': '_EQU_', '_LTE_': '_GT_', '_GTE_': '_LT_', '_LT_': '_GTE_', '_GT_': '_LTE_'}
|
|
MATH_OPERATION_MAP = (
|
|
('==', '_EQU_'),
|
|
('!=', '_NEQ_'),
|
|
('<=', '_LTE_'),
|
|
('>=', '_GTE_'),
|
|
('<', '_LT_'),
|
|
('>', '_GT_')
|
|
)
|
|
MATH_OPERATION = ('AND', 'OR', 'NOT', '_EQU_', '_NEQ_', '_LTE_', '_GTE_', '_LT_', '_GT_', '_LIST_')
|
|
OPERATION_DICT = {'disableif': 'Dif', 'grayoutif': 'Gif', 'suppressif': 'Sif'}
|
|
DATA_TYPE_DICT = {'BOOLEAN': 1, 'UINT8': 1, 'UINT16': 2, 'UINT32': 4, 'UINT64': 8, 'UINTN': 8, 'CHAR8': 1, 'CHAR16': 2}
|
|
SETUP_TYPE_DICT = {'oneof': 5, 'numeric': 0x7, 'numric': 0x7, 'checkbox': 0x6, 'string': 0x8}
|
|
|
|
FFS_FILE_HEADER_SIZE = 0x18
|
|
gEfiFirmwareFileSystemGuid = [0x7A9354D9, 0x0468, 0x444a, 0x81, 0xCE, 0x0B, 0xF6, 0x17, 0xD8, 0x90, 0xDF]
|
|
gEfiFirmwareFileSystem2Guid = [0x8c8ce578, 0x8a3d, 0x4f1c, 0x99, 0x35, 0x89, 0x61, 0x85, 0xc3, 0x2d, 0xd3]
|
|
gEfiFirmwareFileSystem3Guid = [0x5473c07a, 0x3dcb, 0x4dca, 0xbd, 0x6f, 0x1e, 0x96, 0x89, 0xe7, 0x34, 0x9a]
|
|
ZERO_GUID = [0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
|
|
AllFsGuid = [0xFFFFFFFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
|
|
BIOS_KNOBS_BIN_FFS_GUID = "615E6021-603D-4124-B7EA-C48A3737BACD" # Guid of section to be generated
|
|
BIOS_KNOBS_BIN_FV_GUID = "A881D567-6CB0-4EEE-8435-2E72D33E45B5" # Guid of FV to be generated
|
|
|
|
FV_SIGNATURE = 0x4856465F # "_FVH" = 0x4856465F
|
|
|
|
# Executables
|
|
GEN_SEC_BIN = "GenSec"
|
|
GEN_FFS_BIN = "GenFfs"
|
|
FMMT_BIN = "FMMT"
|
|
if sys.platform == "win32":
|
|
# Append .exe extension to executables if windows OS
|
|
GEN_SEC_BIN = "{}.exe".format(GEN_SEC_BIN)
|
|
GEN_FFS_BIN = "{}.exe".format(GEN_FFS_BIN)
|
|
FMMT_BIN = "{}.exe".format(FMMT_BIN)
|
|
|
|
|
|
# Global Values used while parsing
|
|
KNOB_OFFSET = 0
|
|
KNOB_SIZE = 1
|
|
KNOB_EXP = 2
|
|
KNOB_IN_XML = 4
|
|
FIX_KNOB_NAME = 5
|
|
KNOB_TYPE = 6
|
|
BIT_MASK = 7
|
|
DEPEX_MASK = 8
|
|
MASK_VALUES = {1: 0xFFFF, 2: 0xFFFE, 4: 0xFFFC, 8: 0xFFF8}
|
|
STRING_KNOB_SIZE = 0x80
|
|
|
|
InfoList = namedtuple("InfoList", [
|
|
"Offset", "Size", "Depex", "SetupPgPtr",
|
|
"PublishKnobInXml", # for Publishing Knob in XML
|
|
"FixDuplicateKnobName", # for Fixing Knob Name (False = there was no knob with the same name in other NVAR struct)
|
|
"SetupType",
|
|
"KnobNameSuffix" # for Knob Name suffix
|
|
])
|
|
|
|
|
|
# ========================
|
|
# Common Utility functions
|
|
# ========================
|
|
def timeit(method):
|
|
def timed(*args, **kw):
|
|
start_time = time.time()
|
|
result = method(*args, **kw)
|
|
end_time = time.time()
|
|
print('[ParseSetup.py:{}] {:.2f} seconds'.format(method.__name__, (end_time - start_time)))
|
|
if 'log_time' in kw:
|
|
name = kw.get('log_name', method.__name__.upper())
|
|
kw['log_time'][name] = int((end_time - start_time) * 1000)
|
|
return result
|
|
return timed
|
|
|
|
|
|
def hex_string(val, zfill=0):
|
|
"""Hex string with zeroes filled to occupy specified number of characters
|
|
|
|
:param val: input integer value
|
|
:param zfill: total return characters, if less then it will be filled with zeroes
|
|
zeroes are padded as prefix to the string value
|
|
:return:
|
|
"""
|
|
result = "{:x}".format(val).strip().rstrip("L")
|
|
return result.zfill(zfill)
|
|
|
|
|
|
def hex_to_int(buffer_lis):
|
|
"""Convert specified hex buffer list to integer
|
|
|
|
:param buffer_lis: buffer list of hex values
|
|
:return: integer value
|
|
"""
|
|
_bytes = "".join(buffer_lis) if PY2 else bytes(buffer_lis)
|
|
return int(binascii.hexlify(_bytes), 16)
|
|
|
|
|
|
def hexlify(val):
|
|
"""Wrapper to binascii.hexlify for python 2 and 3
|
|
compatibility
|
|
|
|
:param val: binary data (bytes)
|
|
:return: hex representation of binary data
|
|
"""
|
|
if PY2: # For python 2 string and bytes are not separate class
|
|
return binascii.hexlify(val)
|
|
else:
|
|
return binascii.hexlify(val.encode("utf-8")).decode("utf-8")
|
|
|
|
|
|
def read_list(buffer, offset, size):
|
|
"""Read integer value from byte buffer
|
|
|
|
:param buffer: byte buffer
|
|
:param offset: offset to start reading from buffer
|
|
:param size: size to be read from buffer
|
|
:return: integer value of specified byte size
|
|
"""
|
|
if sys.version_info.major == 2:
|
|
return int(binascii.hexlify(string.join(buffer[offset:offset + size][::-1], '')), 16)
|
|
else:
|
|
return int(binascii.hexlify(bytes(buffer[offset:offset + size][::-1])), 16)
|
|
|
|
|
|
def make_directory(dir_path):
|
|
"""Make directory which is to be created
|
|
|
|
:param dir_path: directory which is to be created
|
|
:return:
|
|
"""
|
|
if not os.path.exists(dir_path):
|
|
os.makedirs(dir_path)
|
|
return dir_path
|
|
|
|
|
|
def fetch_guid(buffer_lis, offset):
|
|
"""Read GUID from input buffer
|
|
|
|
:param buffer_lis: buffer list
|
|
:param offset: offset/index location where guid is stored
|
|
:return: GUID as a list of integer
|
|
"""
|
|
if len(buffer_lis) > (offset + 0x10):
|
|
guid_lis = [
|
|
hex_to_int(buffer_lis[(offset + 0x0):(offset + 0x4)][::-1]),
|
|
hex_to_int(buffer_lis[(offset + 0x4):(offset + 0x6)][::-1]),
|
|
hex_to_int(buffer_lis[(offset + 0x6):(offset + 0x8)][::-1])
|
|
]
|
|
guid_lis = guid_lis + [hex_to_int(buffer_lis[(offset + i):(offset + i)]) for i in range(0x8, 0x10 + 1)]
|
|
else:
|
|
guid_lis = ZERO_GUID
|
|
return guid_lis
|
|
|
|
|
|
def replace_not_expression(match):
|
|
"""Replace matched regex DEPEX with negative
|
|
inverted value
|
|
|
|
:param match: regex match
|
|
:return: replace value string for match
|
|
"""
|
|
return match.group(1) + INVERT_DICT.get(match.group(2).strip(), '')
|
|
|
|
|
|
def replace_index_value(match):
|
|
"""Replace matched regex as Index value
|
|
|
|
:param match: regex match
|
|
:return:
|
|
"""
|
|
return '_' + str(eval(match.group(1)))
|
|
|
|
|
|
def process_ro_expression(raw_expression, nvar_details, nvar_table, all_nvar_table, missing_nvars, nvar_ro_lis):
|
|
"""Process DEPEX for Read-only nvars
|
|
|
|
:param raw_expression: Raw Expression
|
|
:param nvar_details: dictionary of Nvar information
|
|
:param nvar_table: dictionary consisting of table of all Nvars
|
|
:param all_nvar_table: dictionary of all Nvars
|
|
:param missing_nvars: dictionary of missing Nvars
|
|
:param nvar_ro_lis: list of read only Nvars
|
|
:return: processed_expression: Processed Expression for read only raw expression
|
|
"""
|
|
processed_expression = raw_expression.replace('(', '( ').replace(')', ' )')
|
|
nvar_name_combination = ''
|
|
for match in re.finditer(r"\s*(\S*?)\s*\.\s*(\S*)\s*", processed_expression):
|
|
if match:
|
|
nvar_struct_name = match.group(1).strip()
|
|
nvar_struct_name = nvar_details[nvar_struct_name]
|
|
knob_name = match.group(2).strip().replace('.', '_')
|
|
if nvar_struct_name not in nvar_table:
|
|
if nvar_struct_name not in missing_nvars:
|
|
missing_nvars[nvar_struct_name] = []
|
|
missing_nvars[nvar_struct_name].append(knob_name)
|
|
else:
|
|
if knob_name not in missing_nvars[nvar_struct_name]:
|
|
missing_nvars[nvar_struct_name].append(knob_name)
|
|
else:
|
|
if nvar_struct_name not in nvar_ro_lis:
|
|
nvar_ro_lis[nvar_struct_name] = []
|
|
nvar_ro_lis[nvar_struct_name].append(knob_name)
|
|
else:
|
|
if knob_name not in nvar_ro_lis[nvar_struct_name]:
|
|
nvar_ro_lis[nvar_struct_name].append(knob_name)
|
|
nvar_name_combination = nvar_name_combination + '|' + nvar_struct_name
|
|
if nvar_name_combination and nvar_name_combination[0] == '|':
|
|
# [TODO] Variable which is getting replaced is used nowhere!!
|
|
nvar_name_combination = nvar_name_combination[1:]
|
|
for match in re.finditer(r"\s*(\w+)\s", processed_expression):
|
|
var = match.group(1).strip()
|
|
if var not in MATH_OPERATION:
|
|
try:
|
|
int(var, 16)
|
|
continue
|
|
except ValueError or TypeError:
|
|
pass
|
|
if (var in all_nvar_table) and (var not in missing_nvars):
|
|
missing_nvars[var] = []
|
|
missing_nvars[var].append(var)
|
|
return processed_expression
|
|
|
|
|
|
def replace_depex(match, duplicate_knobs, all_nvars, nvar_details, missing_nvars, all_knobs):
|
|
"""Replace Dependency Expression (DEPEX)
|
|
|
|
:param match: regex matched DEPEX
|
|
:param duplicate_knobs: dictionary of duplicate knobs
|
|
:param all_nvars: dictionary of all Nvars
|
|
:param nvar_details: dictionary of Nvar information
|
|
:param missing_nvars: dictionary of missing Nvars
|
|
:param all_knobs: dictionary of all knobs
|
|
:return: Replace value for matched DEPEX
|
|
"""
|
|
result = None
|
|
if match:
|
|
nvar_struct_name = nvar_details[match.group(1).strip()]
|
|
knob_name = match.group(2).strip()
|
|
result = ' %s ' % knob_name
|
|
if knob_name in duplicate_knobs and nvar_struct_name in duplicate_knobs[knob_name]:
|
|
result = ' Nvar%d_%s ' % (all_nvars[nvar_struct_name]['bin_var_id'], knob_name)
|
|
elif nvar_struct_name in missing_nvars and len(all_knobs[knob_name]) > 1:
|
|
result = ' Nvar%d_%s ' % (all_nvars[nvar_struct_name]['bin_var_id'], knob_name)
|
|
return result.replace('.', '_')
|
|
|
|
|
|
def process_depex(raw_expression, nvar_table, nvar_details, duplicate_knobs, missing_nvars, all_knobs):
|
|
"""Process Dependency Expression (DEPEX)
|
|
|
|
:param raw_expression: Raw Expression
|
|
:param nvar_table: dictionary consisting of table of all Nvars
|
|
:param nvar_details: dictionary of Nvar information
|
|
:param duplicate_knobs: dictionary of duplicate knobs
|
|
:param missing_nvars: dictionary of missing Nvars
|
|
:param all_knobs: dictionary of all knobs
|
|
:return: Processed DEPEX
|
|
"""
|
|
return re.sub(
|
|
r"\s*(\S*?)\s*\.\s*(\S*)\s*",
|
|
lambda match: replace_depex(match, duplicate_knobs, nvar_table, nvar_details, missing_nvars, all_knobs),
|
|
raw_expression)
|
|
|
|
|
|
def process_print_expression(raw_expression):
|
|
"""Process Print Expression
|
|
|
|
:param raw_expression: Raw Expression
|
|
:return:
|
|
"""
|
|
processed_expression = raw_expression.replace('ideqval ', '').replace('ideqvallist ', '_LIST_ ')
|
|
for sign, string_representation in MATH_OPERATION_MAP:
|
|
processed_expression = processed_expression.replace(sign, " {} ".format(string_representation))
|
|
processed_expression = re.sub("\s+", ' ', processed_expression)
|
|
processed_expression = re.sub("NOT\s*(.*?)(_EQU_|_NEQ_|_LTE_|_GTE_|_LT_|_GT_)",
|
|
replace_not_expression, processed_expression)
|
|
return processed_expression
|
|
|
|
|
|
@timeit
|
|
def clean_vfr_out_file(vfr_out_path, input_vfr_directories, build_path=None):
|
|
"""Clean vfr out files from output directory
|
|
|
|
:param vfr_out_path: location to vfr output files
|
|
:param input_vfr_directories: list of directories from where *.i files are to be parsed
|
|
:param build_path: bios output Build directory path
|
|
:return: None
|
|
"""
|
|
status = 0
|
|
if input_vfr_directories:
|
|
shutil.rmtree(vfr_out_path)
|
|
if not os.path.exists(vfr_out_path):
|
|
os.mkdir(vfr_out_path)
|
|
for input_dir in input_vfr_directories:
|
|
if os.path.exists(input_dir) and vfr_out_path:
|
|
for filename in glob.glob(os.path.join(input_dir, '*.i')):
|
|
shutil.copy(filename, vfr_out_path)
|
|
if build_path:
|
|
for root, directory, files in os.walk(build_path):
|
|
for file in glob.glob(os.path.join(root, "*.i")):
|
|
with open(file, "r") as f:
|
|
line = f.readline().lower().strip()
|
|
if not line:
|
|
continue
|
|
match = re.search(r"\"(.*.vfr)\"", line)
|
|
if match and (not re.search(r"library", match.group(1))):
|
|
out_file = os.path.join(vfr_out_path, os.path.splitext(os.path.basename(file))[0] + '.iout')
|
|
if not os.path.isfile(out_file):
|
|
shutil.copy(file, out_file)
|
|
status += 1
|
|
for file in glob.iglob(vfr_out_path + "/*.iout"):
|
|
outfile = os.path.splitext(file)[0] + '.int'
|
|
with open(outfile, 'w') as out:
|
|
for line in open(file, 'r').readlines():
|
|
if re.search(r"\s*#\s*pragma\s\s*pack\s*\(\s*(.*?)\s*\)\s*", line):
|
|
out.write(line)
|
|
continue
|
|
line = line.split('#')[0]
|
|
line = line.split('//')[0]
|
|
# line = line.strip(' \t')
|
|
if not line.strip():
|
|
continue
|
|
out.write(line.replace(';', ';\n'))
|
|
status += 1
|
|
for file in glob.iglob(vfr_out_path + "/*.int"):
|
|
outfile = os.path.splitext(file)[0] + '.i'
|
|
with open(outfile, 'w') as out:
|
|
skip_if_true = False
|
|
expression_level = 0
|
|
for line in open(file, 'r').readlines():
|
|
if (not line.strip()) and skip_if_true:
|
|
continue
|
|
match = re.search(r"\s*(disableif|grayoutif|suppressif)\s\s*(.*?);", line)
|
|
if match:
|
|
if match.group(2).strip() == 'TRUE':
|
|
skip_if_true = True
|
|
expression_level = expression_level + 1
|
|
continue
|
|
if skip_if_true:
|
|
if re.search(r"\s*(disableif|grayoutif|suppressif)\s\s*", line):
|
|
expression_level = expression_level + 1
|
|
continue
|
|
if (re.search(r"\s*endif\s*", line)) and (expression_level != 0):
|
|
expression_level = expression_level - 1
|
|
if expression_level == 0:
|
|
skip_if_true = False
|
|
continue
|
|
out.write(line)
|
|
status += 1
|
|
return status
|
|
|
|
|
|
# Setup File Parsing
|
|
def parse_header_file(header_file, nvar_list, nvar_table):
|
|
"""Parses Header file for Nvars
|
|
|
|
:param header_file: input header file location
|
|
:param nvar_list: dictionary of Nvars
|
|
:param nvar_table: dictionary of Nvar Table
|
|
:return:
|
|
"""
|
|
nvar_combination_expression = ""
|
|
if not os.path.isfile(header_file):
|
|
print("All Nvars Enabled for this flow")
|
|
else:
|
|
print("Filtered Knobs Enabled for this flow")
|
|
with open(header_file, "r") as hdr_file:
|
|
table_start = False
|
|
nvar_name = None
|
|
nvar_struct = None
|
|
for line in hdr_file.readlines():
|
|
line = line.split('//')[0].strip()
|
|
if not line:
|
|
continue
|
|
if not table_start:
|
|
if re.search(r"\s*VARSTORE_LIST\s\s*mVarstoreList\s*\[\s*\S*\s*\]\s*=", line):
|
|
table_start = True
|
|
else:
|
|
if not nvar_struct:
|
|
match = re.search(r"\s*\"\$(ST|SN)=\s*(.*?)\s*\",", line)
|
|
nvar_struct = match.group(2) if match else None
|
|
# nvar_struct_found = True
|
|
continue
|
|
elif nvar_struct and (not nvar_name):
|
|
match = re.search(r"\s*\"(.*?)\"\s*,", line)
|
|
nvar_name = match.group(1) if match else None
|
|
# nvar_name_found = True
|
|
continue
|
|
elif nvar_name:
|
|
match = re.search(r"\s*{\s*(.*?)\s*}\s*,", line)
|
|
nvar_guid_str = match.group(1) if match else None
|
|
continue
|
|
else:
|
|
if nvar_name and re.search(r"\s*}\s*,", line):
|
|
nvar_struct = nvar_struct if nvar_struct else nvar_name
|
|
nvar_list[nvar_name] = nvar_struct
|
|
nvar_list[nvar_struct] = nvar_struct
|
|
nvar_table[nvar_struct] = {'NvarName': nvar_name, 'NvarGuidStr': nvar_guid_str,
|
|
'NvarSize': 0, 'KnobCount': 0, 'ExpCount': 0, 'DupKnobCount': 0,
|
|
'VarNamesDict': {}, 'DupExp': {}, 'NvarStructDone': False,
|
|
'bin_var_id': 0xFF}
|
|
nvar_combination_expression = "{}{}|{}".format(bool(nvar_combination_expression), nvar_name,
|
|
nvar_struct)
|
|
print("Enabled Nvar for XML CLI knobs = L'{}'".format(nvar_table[nvar_struct]['NvarName']))
|
|
nvar_name = ""
|
|
nvar_struct = ""
|
|
if re.search(r"\s*}\s*;", line):
|
|
table_start = False
|
|
|
|
return nvar_combination_expression
|
|
|
|
|
|
def construct_nvar_buffer(sorted_lis, skip_depex, nvar_details, nvar_table, all_nvars, duplicate_knobs, missing_nvars, all_knobs):
|
|
nvar_id_bin = 0
|
|
result_buffer = b""
|
|
for varstore_struct_name in sorted_lis:
|
|
buffer_str = ""
|
|
if skip_depex:
|
|
nvar_table[varstore_struct_name]['DupKnobCount'] = 0
|
|
bit_knobs = 0
|
|
for bios_knob_name in nvar_table[varstore_struct_name]['VarNamesDict']:
|
|
if bios_knob_name == 'Temp__Struct__Size':
|
|
continue
|
|
if nvar_table[varstore_struct_name]['VarNamesDict'][bios_knob_name][KNOB_IN_XML]:
|
|
bin_knob_name = bios_knob_name
|
|
knob_offset = nvar_table[varstore_struct_name]['VarNamesDict'][bios_knob_name][KNOB_OFFSET]
|
|
knob_size = nvar_table[varstore_struct_name]['VarNamesDict'][bios_knob_name][KNOB_SIZE]
|
|
knob_type = nvar_table[varstore_struct_name]['VarNamesDict'][bios_knob_name][KNOB_TYPE]
|
|
try:
|
|
depex_mask = nvar_table[varstore_struct_name]['VarNamesDict'][bios_knob_name][DEPEX_MASK]
|
|
except:
|
|
depex_mask = 0x7
|
|
if knob_type == SETUP_TYPE_DICT.get("string", 0):
|
|
type_size_bin = hex(((knob_type & 0x8) << 4) + (int(knob_size / 2) & 0x7F))[2:].strip()[0:2]
|
|
bin_knob_name = bin_knob_name.replace("_0", "")
|
|
else:
|
|
bit_mask = nvar_table[varstore_struct_name]['VarNamesDict'][bios_knob_name][BIT_MASK]
|
|
if bit_mask != "":
|
|
bit_knobs = bit_knobs + 1
|
|
bit_mask = bit_mask.split('_')
|
|
bit_offset = int(bit_mask[0], 16)
|
|
bit_size = int(bit_mask[1], 16)
|
|
knob_offset = knob_offset + int(bit_offset/8)
|
|
bit_data = (((bit_size & 0x1F) << 3) + ((bit_offset % 8) & 0x7)) & 0xFF # bit_size[7:3] bit_offset[2:0]
|
|
knob_size = 0xC + ((bit_size >> 5) & 1) # bit_size_BIT05[1:0]
|
|
type_size_bin = (hex(((knob_type & depex_mask) << 4) + (knob_size & 0xF))[2:].strip()+'%02X'%bit_data)[0:4]
|
|
else:
|
|
type_size_bin = hex(((knob_type & depex_mask) << 4) + (knob_size & 0xF))[2:].strip()[0:2]
|
|
bin_offset = hex_string(knob_offset, zfill=4)
|
|
if nvar_table[varstore_struct_name]['VarNamesDict'][bios_knob_name][FIX_KNOB_NAME]:
|
|
bin_knob_name = "Nvar%d_%s" % (nvar_id_bin, bin_knob_name)
|
|
depex = nvar_table[varstore_struct_name]['VarNamesDict'][bios_knob_name][KNOB_EXP].strip()
|
|
if (depex != "TRUE") and (not skip_depex):
|
|
depex = process_depex(depex, all_nvars, nvar_details, duplicate_knobs, missing_nvars, all_knobs)
|
|
if sys.version_info.major == 2:
|
|
bin_name = binascii.hexlify(bin_knob_name).strip()
|
|
if (depex == "TRUE") or skip_depex:
|
|
buffer_str = buffer_str + bin_offset[2:4] + bin_offset[0:2] + type_size_bin + bin_name + '00' + '00'
|
|
else:
|
|
ExpBin = binascii.hexlify(depex).strip()
|
|
buffer_str = buffer_str + bin_offset[2:4] + bin_offset[0:2] + type_size_bin + bin_name + '00' + ExpBin + '00'
|
|
else:
|
|
bin_name = binascii.hexlify(bin_knob_name.strip().encode('utf-8'))
|
|
if (depex == "TRUE") or skip_depex:
|
|
buffer_str = buffer_str + bin_offset[2:4] + bin_offset[0:2] + type_size_bin + bin_name.decode("utf-8") + '00' + '00'
|
|
else:
|
|
ExpBin = binascii.hexlify(depex.strip().encode('utf-8'))
|
|
buffer_str = buffer_str + bin_offset[2:4] + bin_offset[0:2] + type_size_bin + bin_name.decode("utf-8") + '00' + ExpBin.decode("utf-8") + '00'
|
|
|
|
knob_hex_buffer = binascii.unhexlify(buffer_str)
|
|
buffer_str = ""
|
|
for DupCnt in range(0, nvar_table[varstore_struct_name]['DupKnobCount']):
|
|
depex = nvar_table[varstore_struct_name]['DupExp'][DupCnt][1]
|
|
if (depex != "TRUE") and (not skip_depex):
|
|
depex = process_depex(depex, all_nvars, nvar_details, duplicate_knobs, missing_nvars, all_knobs)
|
|
bin_name = hexlify(nvar_table[varstore_struct_name]['DupExp'][DupCnt][0])
|
|
ExpBin = hexlify(depex)
|
|
buffer_str = buffer_str + bin_name.strip() + '00' + ExpBin.strip() + '00'
|
|
if nvar_table[varstore_struct_name]['DupKnobCount'] > 1:
|
|
duplicate_knob_hex_buffer = binascii.unhexlify(buffer_str)
|
|
duplicate_knob_hex_buffer_size = len(duplicate_knob_hex_buffer)
|
|
else:
|
|
duplicate_knob_hex_buffer_size = 0
|
|
knob_hex_buffer_size = len(knob_hex_buffer)
|
|
knob_count = hex(nvar_table[varstore_struct_name]['KnobCount'])[2:].strip().strip('L').zfill(4)
|
|
bit_knob_count = hex(bit_knobs)[2:].strip().strip('L').zfill(4)
|
|
duplicate_knob_count = hex(knob_hex_buffer_size + BIOS_KNOBS_DATA_BIN_HDR_SIZE)[2:].strip().strip('L').zfill(6)
|
|
nvar_packet_size = hex(knob_hex_buffer_size + duplicate_knob_hex_buffer_size + BIOS_KNOBS_DATA_BIN_HDR_SIZE)[2:].strip().strip('L').zfill(6)
|
|
nvar_size = hex(nvar_table[varstore_struct_name]['NvarSize'])[2:].strip().strip('L').zfill(4)
|
|
if len(nvar_table[varstore_struct_name]['NvarName']) >= BIOS_KNOB_BIN_NVAR_NAME_RESERVED:
|
|
print("Nvar Name L\"{}\" too long, please request your Xmlcli engineer to reserve more space in the "
|
|
"Nvar Header \"KNOB_BIN_HDR\"".format(nvar_table[varstore_struct_name]['NvarName']))
|
|
else:
|
|
nvar_name = hexlify(nvar_table[varstore_struct_name]['NvarName']) + hex(0)[2:].strip().zfill((BIOS_KNOB_BIN_NVAR_NAME_RESERVED - len(nvar_table[varstore_struct_name]['NvarName']))*2)
|
|
temp_guid = nvar_table[varstore_struct_name]['NvarGuidStr'].replace('{', '').replace('}', '').strip().split(',')
|
|
temp_guid[0] = temp_guid[0].strip()[2:].zfill(8)
|
|
temp_guid[1] = temp_guid[1].strip()[2:].zfill(4)
|
|
temp_guid[2] = temp_guid[2].strip()[2:].zfill(4)
|
|
nvar_guid = (temp_guid[0][6:8] + temp_guid[0][4:6] + temp_guid[0][2:4] + temp_guid[0][0:2]
|
|
+ temp_guid[1][2:4] + temp_guid[1][0:2] + temp_guid[2][2:4] + temp_guid[2][0:2]
|
|
+ temp_guid[3].strip()[2:].zfill(2) + temp_guid[4].strip()[2:].zfill(2)
|
|
+ temp_guid[5].strip()[2:].zfill(2) + temp_guid[6].strip()[2:].zfill(2)
|
|
+ temp_guid[7].strip()[2:].zfill(2) + temp_guid[8].strip()[2:].zfill(2)
|
|
+ temp_guid[9].strip()[2:].zfill(2) + temp_guid[10].strip()[2:].zfill(2))
|
|
if nvar_id_bin != nvar_table[varstore_struct_name]['bin_var_id']:
|
|
print("This is a Nvar Id problem %s" % varstore_struct_name)
|
|
nvar_buffer = (hexlify("$NVAR") + hex_string(nvar_id_bin, 2)
|
|
+ knob_count[2:4] + knob_count[0:2]
|
|
+ duplicate_knob_count[4:6] + duplicate_knob_count[2:4] + duplicate_knob_count[0:2]
|
|
+ nvar_packet_size[4:6] + nvar_packet_size[2:4] + nvar_packet_size[0:2]
|
|
+ NVAR_NAME_OFFSET_IN_HDR_HEX[0:2] + BIOS_KNOB_BIN_REVISION_HEX[0:2]
|
|
+ nvar_size[2:4] + nvar_size[0:2] + nvar_guid + nvar_name + bit_knob_count[2:4] + bit_knob_count[0:2])
|
|
nvar_id_bin = nvar_id_bin + 1
|
|
result_buffer = result_buffer + binascii.unhexlify(nvar_buffer)
|
|
if knob_hex_buffer_size > 4:
|
|
result_buffer = result_buffer + knob_hex_buffer
|
|
if (duplicate_knob_hex_buffer_size > 2) and (not skip_depex):
|
|
result_buffer = result_buffer + duplicate_knob_hex_buffer
|
|
return result_buffer, nvar_id_bin
|
|
|
|
|
|
def depex_evaluate(read_only_knobs, missing_nvars, nvar_id_bin, nvar_details, nvar_table, all_nvars, all_knobs):
|
|
result_buffer = b""
|
|
for read_only_var_count in range(0, 2):
|
|
read_only_nvars = read_only_knobs if read_only_var_count == 0 else missing_nvars
|
|
for current_nvar in sorted(read_only_nvars, reverse=True):
|
|
buffer_str = ""
|
|
if len(read_only_nvars[current_nvar]) == 0:
|
|
# print ("skipping since its Empty, Nvar = %s" %all_nvars[current_nvar]['var_name'])
|
|
continue
|
|
if current_nvar in nvar_table:
|
|
nvar_bin_var_id = nvar_table[current_nvar]['bin_var_id']
|
|
else:
|
|
nvar_bin_var_id = nvar_id_bin
|
|
nvar_id_bin = nvar_id_bin + 1
|
|
if all_nvars[nvar_details[current_nvar]]['bin_var_id'] != nvar_bin_var_id:
|
|
print("Something is wrong here for %s" % current_nvar)
|
|
bit_knobs = 0
|
|
for knob in read_only_nvars[current_nvar]:
|
|
knob_prefix = "Nvar{}_".format(nvar_bin_var_id) if read_only_var_count == 1 and len(all_knobs[knob]) > 1 else ""
|
|
this_knob = "{}{}".format(knob_prefix, knob)
|
|
knob_offset = all_nvars[current_nvar]['structure'][knob][KNOB_OFFSET]
|
|
knob_size = all_nvars[current_nvar]['structure'][knob][KNOB_SIZE]
|
|
bit_mask = all_nvars[current_nvar]['structure'][knob][BIT_MASK]
|
|
if bit_mask != "":
|
|
bit_knobs = bit_knobs + 1
|
|
bit_mask = bit_mask.split('_')
|
|
bit_offset = int(bit_mask[0], 16)
|
|
bit_size = int(bit_mask[1], 16)
|
|
knob_offset = knob_offset + int(bit_offset/8)
|
|
bit_data = (((bit_size & 0x1F) << 3) + ((bit_offset % 8) & 0x7)) & 0xFF # bit_size[7:3] bit_offset[2:0]
|
|
knob_size = 0xC + ((bit_size >> 5) & 1) # Bitsize_BIT05[1:0]
|
|
type_size_bin = (hex(0x70 + (knob_size & 0xF))[2:].strip()+'%02X'%bit_data)[0:4]
|
|
else:
|
|
type_size_bin = hex(0x70 + knob_size)[2:].strip()[0:2]
|
|
knob_offset = hex(knob_offset)[2:].strip().zfill(4)
|
|
name_binary = hexlify("{}".format(this_knob)).strip()
|
|
buffer_str = (buffer_str + knob_offset[2:4] + knob_offset[0:2] + type_size_bin + name_binary + '00' + '00')
|
|
|
|
knob_hex_buffer = binascii.unhexlify(buffer_str)
|
|
nvar_name_padding = (BIOS_KNOB_BIN_NVAR_NAME_RESERVED - len(all_nvars[current_nvar]['VarName'])) * 2
|
|
nvar_name_str = hexlify(all_nvars[current_nvar]['VarName']) + hex(0)[2:].strip().zfill(nvar_name_padding)
|
|
temp_guid = all_nvars[current_nvar]['Guid'].replace('{', '').replace('}', '').strip().split(',')
|
|
temp_guid[0] = temp_guid[0].strip()[2:].zfill(8)
|
|
temp_guid[1] = temp_guid[1].strip()[2:].zfill(4)
|
|
temp_guid[2] = temp_guid[2].strip()[2:].zfill(4)
|
|
nvar_guid = (temp_guid[0][6:8] + temp_guid[0][4:6] + temp_guid[0][2:4] + temp_guid[0][0:2]
|
|
+ temp_guid[1][2:4] + temp_guid[1][0:2] + temp_guid[2][2:4] + temp_guid[2][0:2]
|
|
+ temp_guid[3].strip()[2:].zfill(2) + temp_guid[4].strip()[2:].zfill(2)
|
|
+ temp_guid[5].strip()[2:].zfill(2) + temp_guid[6].strip()[2:].zfill(2)
|
|
+ temp_guid[7].strip()[2:].zfill(2) + temp_guid[8].strip()[2:].zfill(2)
|
|
+ temp_guid[9].strip()[2:].zfill(2) + temp_guid[10].strip()[2:].zfill(2))
|
|
knob_buffer_size = len(knob_hex_buffer)
|
|
knob_count_str = hex_string(len(read_only_nvars[current_nvar]), zfill=4)
|
|
bit_knob_count = hex(bit_knobs)[2:].strip().strip('L').zfill(4)
|
|
duplicate_knob_count = hex_string(knob_buffer_size + BIOS_KNOBS_DATA_BIN_HDR_SIZE, zfill=6)
|
|
nvar_packet_size = hex_string(knob_buffer_size + BIOS_KNOBS_DATA_BIN_HDR_SIZE, zfill=6)
|
|
nvar_size = hex_string(all_nvars[current_nvar]['Size'], zfill=4)
|
|
if nvar_bin_var_id != all_nvars[nvar_details[current_nvar]]['bin_var_id']:
|
|
print("This is a Nvro Id problem {}".format(current_nvar))
|
|
nvar_buffer_str = (hexlify("$NVRO")
|
|
+ hex(nvar_bin_var_id)[2:].strip().zfill(2)
|
|
+ knob_count_str[2:4] + knob_count_str[0:2]
|
|
+ duplicate_knob_count[4:6] + duplicate_knob_count[2:4] + duplicate_knob_count[0:2]
|
|
+ nvar_packet_size[4:6] + nvar_packet_size[2:4] + nvar_packet_size[0:2]
|
|
+ NVAR_NAME_OFFSET_IN_HDR_HEX[0:2] + BIOS_KNOB_BIN_REVISION_HEX[0:2]
|
|
+ nvar_size[2:4] + nvar_size[0:2] + nvar_guid + nvar_name_str + bit_knob_count[2:4] + bit_knob_count[0:2])
|
|
|
|
result_buffer = result_buffer + binascii.unhexlify(nvar_buffer_str)
|
|
if knob_buffer_size > 4:
|
|
result_buffer = result_buffer + knob_hex_buffer
|
|
return result_buffer, nvar_id_bin
|
|
|
|
|
|
def get_pragma_packed_alignment(pragma_match):
|
|
"""Get alignment to perform based on pragma pack matched
|
|
|
|
:param pragma_match: pragma regex matched to be processed
|
|
:return: tuple of whether it is pragma packed or not and pack alignment
|
|
i.e. (bool, integer) ==> (False, 8)
|
|
"""
|
|
pragma_packed = False
|
|
pack_alignment = 8
|
|
arg_string = pragma_match.group(1).strip()
|
|
if arg_string == "1":
|
|
pragma_packed = True
|
|
elif arg_string in ("2", "4", "8"):
|
|
pragma_packed = False
|
|
pack_alignment = int(arg_string)
|
|
else:
|
|
arg_match = re.search(r"push\s*,\s*(\S*)", arg_string)
|
|
if arg_match and arg_match.group(1) == "1":
|
|
pragma_packed = True
|
|
elif arg_match and arg_match.group(1) in ("2", "4", "8"):
|
|
pragma_packed = False
|
|
pack_alignment = int(arg_match.group(1))
|
|
|
|
return pragma_packed, pack_alignment
|
|
|
|
|
|
def handle_struct(struct_match, is_pragma_packed, pack_alignment, structure, var_offset, header_file, all_nvars, nvar_table, all_knobs):
|
|
"""Handle Structure parsing
|
|
|
|
:param struct_match: regex match for structure
|
|
:param is_pragma_packed: specify whether structure is pragma packed or not
|
|
:param pack_alignment: specify pack alignment
|
|
:param structure: dictionary of structure
|
|
:param var_offset: Variable Offset
|
|
:param header_file: path to the header file location
|
|
:param all_nvars: dictionary of all the nvars
|
|
:param nvar_table:dictionary of the nvar table
|
|
:param all_knobs: dictionary of all the knobs
|
|
:return: whether structure is as nvar or not
|
|
|
|
Just a hint for a beginner to Python: `structure` variable is dictionary which is mutable data in python
|
|
which means python uses same memory reference for the dictionary when you pass it to the function;
|
|
same applies for `all_nvars` and `nvar_table`
|
|
==> For simplicity one can return all these 3 variables and handle as output result
|
|
"""
|
|
struct_name = struct_match.group(1)
|
|
struct_as_nvar = False
|
|
if not is_pragma_packed:
|
|
var_offset = (var_offset + (pack_alignment - 1)) & MASK_VALUES[pack_alignment]
|
|
if struct_name not in all_nvars:
|
|
for ThisMember in structure:
|
|
all_knobs.setdefault(ThisMember, []).append(struct_name)
|
|
all_nvars[struct_name] = {'structure': structure, 'Size': var_offset, 'var_name': '', 'Guid': '', 'bin_var_id': 0xFF}
|
|
if os.path.isfile(header_file) and struct_name in nvar_table and not nvar_table[struct_name]['NvarStructDone']:
|
|
nvar_table[struct_name]['VarNamesDict'] = structure
|
|
nvar_table[struct_name]['NvarStructDone'] = True
|
|
nvar_table[struct_name]['NvarSize'] = var_offset
|
|
struct_as_nvar = True
|
|
if not struct_as_nvar:
|
|
structure["Temp__Struct__Size"] = var_offset
|
|
return struct_as_nvar
|
|
|
|
|
|
def handle_struct_member(line, structure, var_offset, bit_wise, bit_offset, bitwise_varsize, temp_struct, is_pragma_packed, pack_alignment):
|
|
"""Parse Structure for Structure members and update the dictionary of structure
|
|
|
|
:param line: line to be parsed
|
|
:param structure: structure dictionary (input as well as output).. will be updated as python uses same
|
|
reference to dict object
|
|
:param var_offset: offset value of variable
|
|
:param bit_wise: specify whether the operation is bit wise or not
|
|
:param bit_offset: offset bit
|
|
:param temp_struct: temporary structure dictionary
|
|
:param is_pragma_packed: specify whether pragma packed structure or not
|
|
:param pack_alignment: pragma pack alignment of structure
|
|
:return: Updated values of `structure`, `var_offset`, `bit_wise`, `bit_offset`
|
|
"""
|
|
standard_data_type = False
|
|
bit_size = 0
|
|
var_size = 1
|
|
for match in re.finditer(r"\s*(BOOLEAN|UINT\S*|CHAR\S*)\s\s*(.*?);", line):
|
|
if match:
|
|
var_size = (DATA_TYPE_DICT[match.group(1)] & 0xF)
|
|
var_name = match.group(2).strip()
|
|
total_elements = 1
|
|
is_array_var = False
|
|
array_match = re.search("(\S*)\s*:\s*(\S*)\s*", var_name)
|
|
if array_match:
|
|
var_name = array_match.group(1)
|
|
bit_size = int(array_match.group(2))
|
|
bit_wise = True
|
|
if ((bitwise_varsize != var_size) and (bit_offset != 0)):
|
|
var_offset = var_offset + bitwise_varsize
|
|
bit_offset = 0
|
|
bitwise_varsize = var_size
|
|
else:
|
|
if bit_wise:
|
|
bit_wise = False
|
|
bit_offset = 0
|
|
var_offset = var_offset + bitwise_varsize
|
|
if (not is_pragma_packed) and (var_size != 1):
|
|
var_offset = (var_offset + (var_size - 1)) & MASK_VALUES[var_size]
|
|
array_match = re.search("(\S*)\s*\[\s*(\S*)\s*\]", var_name)
|
|
if array_match:
|
|
var_name = array_match.group(1)
|
|
total_elements = eval(array_match.group(2))
|
|
is_array_var = True
|
|
for count in range(0, total_elements):
|
|
if bit_wise:
|
|
if ((var_size*8) < bit_offset + bit_size):
|
|
bit_offset = 0
|
|
var_offset = var_offset + var_size
|
|
bit_mask = "%X_%X" %(bit_offset, bit_size)
|
|
bit_offset = bit_offset + bit_size
|
|
else:
|
|
bit_mask = ""
|
|
info_list = InfoList(var_offset, var_size, "", "", False, False, 0, bit_mask)
|
|
if is_array_var:
|
|
structure["{}_{}".format(var_name, count)] = list(info_list)
|
|
else:
|
|
structure[var_name] = list(info_list)
|
|
if not bit_wise:
|
|
var_offset = var_offset + var_size
|
|
standard_data_type = True
|
|
if not standard_data_type:
|
|
match = re.search(r"\s*(\S*)\s\s*(.*?);", line)
|
|
if match:
|
|
parent = match.group(1)
|
|
child_name = match.group(2)
|
|
if temp_struct.get(parent, None):
|
|
if not is_pragma_packed:
|
|
var_offset = (var_offset + (pack_alignment - 1)) & MASK_VALUES[pack_alignment]
|
|
is_array_var = False
|
|
total_elements = 1
|
|
array_match = re.search("(\S*)\s*\[\s*(\S*)\s*\]", child_name)
|
|
if array_match:
|
|
total_elements = eval(array_match.group(2))
|
|
is_array_var = True
|
|
for count in range(0, total_elements):
|
|
if is_array_var:
|
|
child_name = "%s_%s" % (array_match.group(1), count)
|
|
for member in temp_struct[parent]:
|
|
if member == "Temp__Struct__Size":
|
|
continue
|
|
info_list = InfoList(temp_struct[parent][member][KNOB_OFFSET] + var_offset,
|
|
temp_struct[parent][member][KNOB_SIZE], "", "", False, False, 0,
|
|
temp_struct[parent][member][BIT_MASK])
|
|
nested_member_name = "%s_%s" % (child_name, member)
|
|
structure[nested_member_name] = list(info_list)
|
|
var_offset = var_offset + temp_struct[parent]["Temp__Struct__Size"]
|
|
|
|
return structure, var_offset, bit_wise, bit_offset, var_size, bitwise_varsize
|
|
|
|
|
|
def handle_expression(line, expression, nvar_details, expression_level, published_knobs, nvar_table, all_knobs, final_expression_name, duplicate_knobs, previous_line):
|
|
"""Parse the Expression line and update the dictionaries for nvar, knobs and final expression
|
|
|
|
:param line: input line to be parse
|
|
:param expression: nvar combination expression for line to be parsed for
|
|
:param nvar_details: dictionary consisting of details of nvar
|
|
:param expression_level: level of expression
|
|
:param published_knobs: dictionary consisting of published knobs
|
|
:param nvar_table: nvar table dictionary
|
|
:param all_knobs: dictionary containing all the knobs
|
|
:param final_expression_name: final expression name
|
|
:param duplicate_knobs: dictionary consisting duplicate knobs
|
|
:param previous_line: previously parsed line
|
|
:return: None
|
|
but python updates the dictionaries:
|
|
`nvar_details`, `nvar_table`, `all_knobs`, `duplicate_knobs`, `previous_line`
|
|
|
|
"""
|
|
for match in re.finditer(r"(\s*(\S*)\s*varid\s*=\s*)({})\s*\.\s*(\S*)\s*,".format(expression), line):
|
|
if match:
|
|
_type = match.group(2)
|
|
nvar_type = match.group(3)
|
|
if nvar_type in nvar_details:
|
|
varstore_struct_name = nvar_details[nvar_type]
|
|
else:
|
|
continue
|
|
org_variable = match.group(4).replace(".", "_")
|
|
if _type == "":
|
|
match_type = re.search(r"\s*(numric|numeric|oneof|checkbox|string)\s*", previous_line)
|
|
if match_type:
|
|
_type = match_type.group(1)
|
|
else:
|
|
continue
|
|
elif _type in ("password", "date", "time"):
|
|
continue
|
|
if _type == "string":
|
|
variable = org_variable + '_0'
|
|
else:
|
|
variable = re.sub("\[\s*(.*?)\s*\]", replace_index_value, org_variable)
|
|
final_expression = "TRUE"
|
|
if expression_level > 0:
|
|
final_expression = process_print_expression(final_expression_name[1])
|
|
if (expression_level > 1) and (final_expression.replace(" ", "") != "(FALSE)"):
|
|
for ExpCnt in range(2, (expression_level + 1)):
|
|
current_expression = process_print_expression(final_expression_name[ExpCnt])
|
|
if current_expression.replace(" ", "") == "(FALSE)":
|
|
final_expression = "( FALSE )"
|
|
break
|
|
if current_expression not in final_expression:
|
|
final_expression = final_expression + " _AND_ " + current_expression
|
|
if ((final_expression.replace(" ", "") == "(FALSE)")
|
|
or (final_expression.replace(" ", "") == "Sif(TRUE)")):
|
|
continue
|
|
final_expression = re.sub("\[\s*(.*?)\s*\]", replace_index_value, final_expression)
|
|
if (varstore_struct_name, variable) in published_knobs:
|
|
knob_published = published_knobs[varstore_struct_name, variable]
|
|
if expression_level > 0:
|
|
nvar_table[varstore_struct_name]['ExpCount'] = nvar_table[varstore_struct_name]['ExpCount'] + 1
|
|
else:
|
|
final_expression = "TRUE"
|
|
duplicate_idx = nvar_table[varstore_struct_name]['DupKnobCount']
|
|
nvar_table[varstore_struct_name]['DupExp'][duplicate_idx] = [variable, final_expression]
|
|
nvar_table[varstore_struct_name]['DupKnobCount'] = duplicate_idx + 1
|
|
published_knobs[varstore_struct_name, variable] = knob_published + 1
|
|
else:
|
|
published_knobs[varstore_struct_name, variable] = 1
|
|
if expression_level > 0:
|
|
nvar_table[varstore_struct_name]['ExpCount'] = nvar_table[varstore_struct_name]['ExpCount'] + 1
|
|
else:
|
|
final_expression = "TRUE"
|
|
nvar_table[varstore_struct_name]['KnobCount'] = nvar_table[varstore_struct_name]['KnobCount'] + 1
|
|
nvar_table[varstore_struct_name]['VarNamesDict'][variable][KNOB_EXP] = final_expression
|
|
nvar_table[varstore_struct_name]['VarNamesDict'][variable][KNOB_IN_XML] = True
|
|
nvar_table[varstore_struct_name]['VarNamesDict'][variable][KNOB_TYPE] = SETUP_TYPE_DICT.get(_type, 0)
|
|
if _type == "string":
|
|
nvar_table[varstore_struct_name]['VarNamesDict'][variable][KNOB_SIZE] = (0x7F * 2)
|
|
for string_knob_size in range(1, STRING_KNOB_SIZE):
|
|
_variable = "{}_{}".format(org_variable, string_knob_size)
|
|
if _variable not in nvar_table[varstore_struct_name]['VarNamesDict']:
|
|
nvar_table[varstore_struct_name]['VarNamesDict'][variable][KNOB_SIZE] = (
|
|
string_knob_size * 2)
|
|
break
|
|
if len(all_knobs[variable]) > 1:
|
|
if variable in duplicate_knobs:
|
|
nvar_table[varstore_struct_name]['VarNamesDict'][variable][FIX_KNOB_NAME] = True
|
|
else:
|
|
duplicate_knobs[variable] = copy.deepcopy(all_knobs[variable])
|
|
duplicate_knobs[variable].remove(varstore_struct_name)
|
|
return expression_level
|
|
|
|
|
|
@timeit
|
|
def parse_setup_files(vfr_output_file_path, header_file_path, knobs_bin_file, skip_depex=False):
|
|
"""Parse Setup Files from Build Folder
|
|
|
|
:param vfr_output_file_path: vfr out put files
|
|
:param header_file_path: header file location
|
|
:param knobs_bin_file: bios knob data bin file location
|
|
:param skip_depex: specify whether to skip depex check or not
|
|
:return:
|
|
"""
|
|
final_expression_name = {}
|
|
temp_struct = {}
|
|
nvar_table = {}
|
|
all_nvars = {}
|
|
all_knobs = {}
|
|
duplicate_knobs = {}
|
|
nvar_details = {}
|
|
missing_nvars = {}
|
|
read_only_nvars = {}
|
|
published_knobs = {}
|
|
varstore_start = False
|
|
expression_level = 0
|
|
output_path = os.path.dirname(header_file_path)
|
|
var_offset = 0
|
|
var_size = 1
|
|
structure_start = False
|
|
typedef_start = False
|
|
is_pragma_packed = False
|
|
pack_alignment = 8
|
|
|
|
nvar_combination_expression = parse_header_file(header_file=header_file_path, nvar_list=nvar_details, nvar_table=nvar_table)
|
|
|
|
final_expression_name[expression_level] = "TRUE"
|
|
for vfr_output_file in glob.iglob(vfr_output_file_path + "/*.i"):
|
|
# print(f)
|
|
match = re.search(r".*\\(\S*).i", vfr_output_file)
|
|
if match:
|
|
print("Parsing Hii elements from %s.i" % match.group(1))
|
|
current_line = ""
|
|
remove_expression = False
|
|
expression_level = 0
|
|
goto_expression_prefix = {}
|
|
varstore_struct_name = ''
|
|
structure = {}
|
|
bit_wise = False
|
|
bit_offset = 0
|
|
bitwise_varsize = 1
|
|
for line in open(vfr_output_file, "r").readlines():
|
|
if not structure_start: # Validate Pragma match
|
|
match = re.search(r"\s*#\s*pragma\s\s*pack\s*\(\s*(.*?)\s*\)\s*", line)
|
|
if match:
|
|
is_pragma_packed, pack_alignment = get_pragma_packed_alignment(pragma_match=match)
|
|
continue
|
|
|
|
# Start Processing lines
|
|
line = line.split('#')[0].split('//')[0].strip()
|
|
if not line: # Skip empty lines
|
|
continue
|
|
previous_line = current_line
|
|
current_line = line
|
|
|
|
# Parse Structure
|
|
# i.e. typedef struct {
|
|
match = re.search(r"\s*typedef\s\s*struct\s*", line)
|
|
if match: # structure found
|
|
structure_start = True
|
|
bit_wise = False
|
|
bit_offset = 0
|
|
structure = {}
|
|
continue
|
|
else:
|
|
if re.search(r"\s*typedef\s*", line):
|
|
typedef_start = True
|
|
continue
|
|
if typedef_start and re.search(r"\s*struct\s*", line):
|
|
typedef_start = False
|
|
structure_start = True
|
|
bit_wise = False
|
|
bit_offset = 0
|
|
structure = {}
|
|
continue
|
|
|
|
if structure_start:
|
|
struct_match = re.search(r"\s*}\s*(\S*)\s*;", line)
|
|
if struct_match:
|
|
structure_start = False
|
|
if bit_wise:
|
|
bit_wise = False
|
|
bit_offset = 0
|
|
var_offset = var_offset + var_size
|
|
# dictionaries, structure, all_nvars, nvar_table and all_knobs will be updated
|
|
struct_as_nvar = handle_struct(struct_match, is_pragma_packed, pack_alignment, structure, var_offset,
|
|
header_file=header_file_path, all_nvars=all_nvars,
|
|
nvar_table=nvar_table, all_knobs=all_knobs)
|
|
if struct_match.group(1) and not struct_as_nvar:
|
|
temp_struct[struct_match.group(1)] = structure
|
|
var_offset = 0
|
|
continue
|
|
else:
|
|
structure, var_offset, bit_wise, bit_offset, var_size, bitwise_varsize = handle_struct_member(line, structure, var_offset, bit_wise, bit_offset,bitwise_varsize, temp_struct, is_pragma_packed, pack_alignment)
|
|
|
|
# Parse Var Store Example lines listed below:
|
|
# efivarstore SA_SETUP, varid = 2, attribute = 0x7, name = SaSetup, guid = { 0x72c5e28c, 0x7783, 0x43a1, { 0x87, 0x67, 0xfa, 0xd7, 0x3f, 0xcc, 0xaf, 0xa4 } };
|
|
# varstore SYSTEM_ACCESS, varid = 0xF000, name = SystemAccess, guid = { 0xE770BB69, 0xBCB4, 0x4D04, { 0x9E, 0x97, 0x23, 0xFF, 0x94, 0x56, 0xFE, 0xAC }};
|
|
match = re.search(r"\s*(efivarstore|varstore)\s*(.*?)\s*,", line)
|
|
if match:
|
|
current_struct_var_name = match.group(2).strip()
|
|
if current_struct_var_name in all_nvars:
|
|
varstore_start = True
|
|
varstore_struct_name = current_struct_var_name
|
|
elif current_struct_var_name in DATA_TYPE_DICT:
|
|
varstore_struct_name = current_struct_var_name
|
|
varstore_start = True
|
|
|
|
if varstore_start:
|
|
match = re.search(r"\s*name\s*=\s*(.*?)\s*,\s*guid\s*=\s*(.*?)\s*;", line)
|
|
if match:
|
|
if varstore_struct_name in DATA_TYPE_DICT:
|
|
all_nvars[match.group(1).strip()] = {}
|
|
all_nvars[match.group(1).strip()]['Size'] = DATA_TYPE_DICT[varstore_struct_name]
|
|
varstore_struct_name = match.group(1).strip()
|
|
info_list = InfoList(0, all_nvars[varstore_struct_name]['Size'], "", "", False, False, 0, '')
|
|
structure[varstore_struct_name] = list(info_list)
|
|
all_nvars[varstore_struct_name]['structure'] = {}
|
|
all_nvars[varstore_struct_name]['structure'][varstore_struct_name] = list(info_list)
|
|
all_nvars[varstore_struct_name]['VarName'] = match.group(1).strip()
|
|
all_nvars[varstore_struct_name]['Guid'] = match.group(2).strip()
|
|
if varstore_struct_name not in nvar_table:
|
|
nvar_details[all_nvars[varstore_struct_name]['VarName']] = varstore_struct_name
|
|
nvar_details[varstore_struct_name] = varstore_struct_name
|
|
if not os.path.isfile(header_file_path):
|
|
nvar_table[varstore_struct_name] = {
|
|
'NvarName': all_nvars[varstore_struct_name]['VarName'],
|
|
'NvarGuidStr': all_nvars[varstore_struct_name]['Guid'],
|
|
'NvarSize': all_nvars[varstore_struct_name]['Size'], 'KnobCount': 0, 'ExpCount': 0,
|
|
'DupKnobCount': 0, 'VarNamesDict': all_nvars[varstore_struct_name]['structure'],
|
|
'DupExp': {}, 'NvarStructDone': True, 'bin_var_id': 0xFF}
|
|
nvar_combination_expression = "{}{}{}|{}".format(
|
|
nvar_combination_expression, "|" if nvar_combination_expression else "",
|
|
nvar_table[varstore_struct_name]['NvarName'], varstore_struct_name)
|
|
varstore_start = False
|
|
continue
|
|
else:
|
|
match = re.search(r"\s*name\s*=\s*(.*?)\s*,", line)
|
|
if match:
|
|
if varstore_struct_name in DATA_TYPE_DICT:
|
|
all_nvars[match.group(1).strip()] = {}
|
|
all_nvars[match.group(1).strip()]['Size'] = DATA_TYPE_DICT[varstore_struct_name]
|
|
varstore_struct_name = match.group(1).strip()
|
|
info_list = InfoList(0, all_nvars[varstore_struct_name]['Size'], "", "", False, False, 0, "")
|
|
structure[varstore_struct_name] = list(info_list)
|
|
all_nvars[varstore_struct_name]['structure'] = {}
|
|
all_nvars[varstore_struct_name]['structure'][varstore_struct_name] = list(info_list)
|
|
all_nvars[varstore_struct_name]['VarName'] = match.group(1).strip()
|
|
continue
|
|
match = re.search(r"\s*guid\s*=\s*(.*?)\s*;", line)
|
|
if match:
|
|
all_nvars[varstore_struct_name]['Guid'] = match.group(1).strip()
|
|
varstore_start = False
|
|
if varstore_struct_name not in nvar_table:
|
|
nvar_details[all_nvars[varstore_struct_name]['VarName']] = varstore_struct_name
|
|
nvar_details[varstore_struct_name] = varstore_struct_name
|
|
if not os.path.isfile(header_file_path):
|
|
nvar_table[varstore_struct_name] = {
|
|
'NvarName': all_nvars[varstore_struct_name]['VarName'],
|
|
'NvarGuidStr': all_nvars[varstore_struct_name]['Guid'],
|
|
'NvarSize': all_nvars[varstore_struct_name]['Size'], 'KnobCount': 0,
|
|
'ExpCount': 0, 'DupKnobCount': 0,
|
|
'VarNamesDict': all_nvars[varstore_struct_name]['structure'], 'DupExp': {},
|
|
'NvarStructDone': True, 'bin_var_id': 0xFF}
|
|
nvar_combination_expression = "{}{}{}|{}".format(
|
|
nvar_combination_expression, "|" if nvar_combination_expression else "",
|
|
nvar_table[varstore_struct_name]['NvarName'], varstore_struct_name)
|
|
continue
|
|
|
|
if remove_expression:
|
|
match = re.search(r"\s*(.*?);", line)
|
|
if match:
|
|
final_expression_name[expression_level] = final_expression_name[expression_level] + ' ' + match.group(1).strip() + ')'
|
|
remove_expression = False
|
|
continue
|
|
else:
|
|
match = re.search(r"\s*(.*)\s*", line)
|
|
if match:
|
|
final_expression_name[expression_level] = final_expression_name[expression_level] + ' ' + match.group(1)
|
|
continue
|
|
else:
|
|
match = re.search(r"\s*(disableif|grayoutif|suppressif)\s\s*(.*?);", line)
|
|
if match:
|
|
expression_level = expression_level + 1
|
|
operation = OPERATION_DICT.get(match.group(1).strip(), '??')
|
|
final_expression_name[expression_level] = operation + '(' + match.group(2).strip() + ')'
|
|
remove_expression = False
|
|
continue
|
|
else:
|
|
match = re.search(r"\s*(disableif|grayoutif|suppressif)\s\s*(.*)\s*", line)
|
|
if match:
|
|
expression_level = expression_level + 1
|
|
operation = OPERATION_DICT.get(match.group(1).strip(), '??')
|
|
final_expression_name[expression_level] = operation + '(' + match.group(2).strip()
|
|
remove_expression = True
|
|
continue
|
|
|
|
for match in re.finditer(r"\s*endif\s*", line):
|
|
if match and (expression_level != 0):
|
|
final_expression_name.pop(expression_level)
|
|
expression_level = expression_level - 1
|
|
|
|
if expression_level == 0:
|
|
final_expression_name = {0: "TRUE"}
|
|
|
|
match = re.search(r"\s*goto\s*(.*?)\s*,", line)
|
|
if match:
|
|
goto_form_id = match.group(1).strip()
|
|
if expression_level > 0:
|
|
goto_expression_prefix[goto_form_id] = final_expression_name.copy()
|
|
|
|
match = re.search(r"\s*form\s*formid\s*=\s*(.*?)\s*,", line)
|
|
if match:
|
|
current_form_id = match.group(1).strip()
|
|
expression_level = 0
|
|
final_expression_name = {0: "TRUE"}
|
|
if current_form_id in goto_expression_prefix:
|
|
expression_level = len(goto_expression_prefix[current_form_id]) - 1
|
|
if expression_level > 0:
|
|
final_expression_name = goto_expression_prefix[current_form_id].copy()
|
|
|
|
if re.search(r"\s*endform\s*;\s*", line):
|
|
expression_level = 0
|
|
final_expression_name = {0: "TRUE"}
|
|
|
|
handle_expression(line, nvar_combination_expression, nvar_details, expression_level, published_knobs,
|
|
nvar_table, all_knobs, final_expression_name, duplicate_knobs, previous_line)
|
|
|
|
# print(nvar_combination_expression)
|
|
for varstore_struct_name in sorted(nvar_table):
|
|
# print(varstore_struct_name)
|
|
# print(nvar_table[varstore_struct_name]['NvarName'])
|
|
# print(nvar_table[varstore_struct_name]['NvarGuidStr'])
|
|
# print(nvar_table[varstore_struct_name]['NvarSize'])
|
|
# print(nvar_table[varstore_struct_name]['KnobCount'])
|
|
if nvar_table[varstore_struct_name]['KnobCount'] == 0:
|
|
# delete entries for NVAR's that don't hold any Bios Knobs
|
|
nvar_table.pop(varstore_struct_name)
|
|
continue
|
|
# Adding Boot order Variable manually
|
|
nvar_table['BootOrder'] = {'NvarName': 'BootOrder',
|
|
'NvarGuidStr': '0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C',
|
|
'NvarSize': 0, 'KnobCount': 0, 'ExpCount': 0, 'DupKnobCount': 0, 'VarNamesDict': {},
|
|
'DupExp': {}, 'NvarStructDone': False, 'bin_var_id': 0xFF}
|
|
|
|
for varstore_struct_name in nvar_table:
|
|
for variable in nvar_table[varstore_struct_name]['VarNamesDict']:
|
|
if variable == 'Temp__Struct__Size':
|
|
continue
|
|
visual_expression = nvar_table[varstore_struct_name]['VarNamesDict'][variable][KNOB_EXP]
|
|
if visual_expression != "TRUE":
|
|
visual_expression = process_ro_expression(visual_expression, nvar_details, nvar_table, all_nvars, missing_nvars,
|
|
read_only_nvars)
|
|
nvar_table[varstore_struct_name]['VarNamesDict'][variable][KNOB_EXP] = visual_expression
|
|
for DupCountId in nvar_table[varstore_struct_name]['DupExp']:
|
|
visual_expression = nvar_table[varstore_struct_name]['DupExp'][DupCountId][1]
|
|
if visual_expression != "TRUE":
|
|
visual_expression = process_ro_expression(visual_expression, nvar_details, nvar_table, all_nvars, missing_nvars,
|
|
read_only_nvars)
|
|
nvar_table[varstore_struct_name]['DupExp'][DupCountId][1] = visual_expression
|
|
|
|
temp_vars = {varstore_name: nvar_table[varstore_name]['KnobCount'] for varstore_name in nvar_table}
|
|
temp_vars = sorted(temp_vars.items(), key=lambda x: x[1], reverse=True)
|
|
sorted_lis = [_var[0] for _var in temp_vars]
|
|
bin_var_id = 0
|
|
# print ("-------------------------------------------")
|
|
for varstore_struct_name in sorted_lis:
|
|
if varstore_struct_name in all_nvars:
|
|
all_nvars[varstore_struct_name]['bin_var_id'] = bin_var_id
|
|
nvar_table[varstore_struct_name]['bin_var_id'] = bin_var_id
|
|
# print(varstore_struct_name, bin_var_id, nvar_table[varstore_struct_name]['KnobCount'])
|
|
bin_var_id = bin_var_id + 1
|
|
if varstore_struct_name in read_only_nvars:
|
|
temp_lis = copy.deepcopy(read_only_nvars[varstore_struct_name])
|
|
for bios_knob_name in temp_lis:
|
|
if nvar_table[varstore_struct_name]['VarNamesDict'][bios_knob_name][KNOB_IN_XML]:
|
|
read_only_nvars[varstore_struct_name].remove(bios_knob_name)
|
|
nvar_table[varstore_struct_name]['VarNamesDict'][bios_knob_name].append(0x3)
|
|
# print ("-------------------------------------------")
|
|
if not skip_depex:
|
|
for varstore_struct_name in list(reversed(sorted(read_only_nvars))):
|
|
if (len(read_only_nvars[varstore_struct_name]) == 0) or (nvar_table[varstore_struct_name]['KnobCount'] != 0):
|
|
continue
|
|
if varstore_struct_name in nvar_table:
|
|
all_nvars[nvar_details[varstore_struct_name]]['bin_var_id'] = nvar_table[varstore_struct_name]['bin_var_id']
|
|
else:
|
|
all_nvars[nvar_details[varstore_struct_name]]['bin_var_id'] = bin_var_id
|
|
bin_var_id = bin_var_id + 1
|
|
# print (nvar_details[varstore_struct_name], all_nvars[nvar_details[varstore_struct_name]]['bin_var_id'])
|
|
for varstore_struct_name in list(reversed(sorted(missing_nvars))):
|
|
if len(missing_nvars[varstore_struct_name]) == 0:
|
|
continue
|
|
if varstore_struct_name in nvar_table:
|
|
all_nvars[nvar_details[varstore_struct_name]]['bin_var_id'] = nvar_table[varstore_struct_name]['bin_var_id']
|
|
else:
|
|
all_nvars[nvar_details[varstore_struct_name]]['bin_var_id'] = bin_var_id
|
|
bin_var_id = bin_var_id + 1
|
|
# print (nvar_details[varstore_struct_name], all_nvars[nvar_details[varstore_struct_name]]['bin_var_id'])
|
|
# print ("-------------------------------------------")
|
|
|
|
# Done with all required processing and DB gathering, lets create the binary now.
|
|
|
|
knobs_bin_file = os.path.join(output_path, 'BiosKnobsData.bin') if ((not knobs_bin_file) or (knobs_bin_file == "dummy")) else knobs_bin_file
|
|
result_buffer, nvar_id_bin = construct_nvar_buffer(sorted_lis, skip_depex, nvar_details, nvar_table, all_nvars, duplicate_knobs, missing_nvars, all_knobs)
|
|
|
|
# print ("=========================================================================")
|
|
# for VarStructName in read_only_nvars:
|
|
# print (VarStructName)
|
|
# for knob_count in read_only_nvars[VarStructName]:
|
|
# print ('\t'+knob_count)
|
|
# print ("=========================================================================")
|
|
# for VarStructName in missing_nvars:
|
|
# print (VarStructName)
|
|
# for knob_count in missing_nvars[VarStructName]:
|
|
# print ('\t'+knob_count)
|
|
# print ("=========================================================================")
|
|
if not skip_depex:
|
|
_result_buffer, nvar_id_bin = depex_evaluate(read_only_knobs=read_only_nvars, missing_nvars=missing_nvars,
|
|
nvar_id_bin=nvar_id_bin, nvar_details=nvar_details,
|
|
nvar_table=nvar_table, all_nvars=all_nvars, all_knobs=all_knobs)
|
|
result_buffer = result_buffer + _result_buffer
|
|
|
|
# Writing buffer to file...
|
|
knobs_bin_file = os.path.join(output_path, 'BiosKnobsData.bin') if ((not knobs_bin_file) or (knobs_bin_file == "dummy")) else knobs_bin_file
|
|
with open(knobs_bin_file, 'wb') as KnobsBin:
|
|
KnobsBin.write(result_buffer)
|
|
|
|
# for VarStructName in all_nvars:
|
|
# print(VarStructName)
|
|
# print('\t'+all_nvars[VarStructName]['VarName'])
|
|
# print('\t'+all_nvars[VarStructName]['Guid'])
|
|
# print(all_nvars[VarStructName]['Size'])
|
|
# exit(1)
|
|
|
|
# DebugOut.close()
|
|
# return nvar_table
|
|
|
|
|
|
def get_fv_main_component(bios_rom_file, ffs_guid, output_file):
|
|
"""
|
|
|
|
:param bios_rom_file: BIOS Rom Image location
|
|
:param ffs_guid: FFS Guid
|
|
:param output_file: Output file location
|
|
:return:
|
|
"""
|
|
with open(bios_rom_file, "rb") as bios_bin:
|
|
bios_bin_buffer_lis = list(bios_bin.read())
|
|
bios_fv_base = 0
|
|
for _ in range(0, len(bios_bin_buffer_lis)):
|
|
fv_zero_vector = fetch_guid(bios_bin_buffer_lis, bios_fv_base)
|
|
fv_guid = fetch_guid(bios_bin_buffer_lis, (bios_fv_base + 0x10))
|
|
if (fv_zero_vector == ZERO_GUID) and (fv_guid != ZERO_GUID): # Every valid FV needs to have this zero vector.
|
|
fv_size = read_list(bios_bin_buffer_lis, (bios_fv_base + 0x20), 8)
|
|
if (fv_guid == AllFsGuid) and (fv_size == 0xFFFFFFFFFFFFFFFF):
|
|
bios_fv_base = ((bios_fv_base & 0xFFFFF000) + 0x1000)
|
|
continue # InValid FV, skip this iteration
|
|
if fv_guid == gEfiFirmwareFileSystemGuid:
|
|
file_system_type = 1
|
|
elif fv_guid == gEfiFirmwareFileSystem2Guid:
|
|
file_system_type = 2
|
|
elif fv_guid == gEfiFirmwareFileSystem3Guid:
|
|
file_system_type = 3
|
|
else:
|
|
file_system_type = 0
|
|
fv_signature = read_list(bios_bin_buffer_lis, (bios_fv_base + 0x28), 4)
|
|
if fv_signature != FV_SIGNATURE: # "_FVH" = 0x4856465F
|
|
bios_fv_base = ((bios_fv_base & 0xFFFFF000) + 0x1000)
|
|
continue # InValid FV, skip this iteration
|
|
fv_header_length = read_list(bios_bin_buffer_lis, (bios_fv_base + 0x30), 2)
|
|
extended_header_offset = read_list(bios_bin_buffer_lis, (bios_fv_base + 0x34), 2)
|
|
if extended_header_offset:
|
|
fv_header_length = extended_header_offset + 0x10 + 4
|
|
bios_fv_ffs_base = bios_fv_base + fv_header_length
|
|
file_system_base = (bios_fv_ffs_base + 7) & 0xFFFFFFF8 # because FileSystem sits on a 8 byte boundary
|
|
if file_system_base >= (bios_fv_base + fv_size):
|
|
bios_fv_base = (bios_fv_base + fv_size)
|
|
continue
|
|
for FfsCount in range(0, 1):
|
|
if file_system_type == 0:
|
|
break
|
|
bios_fv_ffs_base = (bios_fv_ffs_base + 7) & 0xFFFFFFF8 # this is because FFS sits on a 8 byte boundary
|
|
if bios_fv_ffs_base >= (bios_fv_base + fv_size):
|
|
break
|
|
_ffs_guid = fetch_guid(bios_bin_buffer_lis, bios_fv_ffs_base)
|
|
if _ffs_guid == ZERO_GUID:
|
|
break
|
|
if _ffs_guid == ffs_guid:
|
|
with open(output_file, 'wb') as ffs_file:
|
|
if sys.version_info.major == 2:
|
|
ffs_file.write(string.join(bios_bin_buffer_lis[bios_fv_base:bios_fv_base + fv_size], ''))
|
|
else:
|
|
ffs_file.write(bytes(bios_bin_buffer_lis[bios_fv_base:bios_fv_base + fv_size]))
|
|
return
|
|
bios_fv_base = (bios_fv_base + fv_size)
|
|
else:
|
|
bios_fv_base = ((bios_fv_base & 0xFFFFF000) + 0x1000) # InValid FV, Adjust FvBaseAccordingly
|
|
|
|
|
|
@timeit
|
|
def post_build(bios_build_dir, vfr_output_file_path, header_file_path, knobs_bin_file, skip_depex, xmlcli_build_dir=None, input_vfr_directories=[], process_vfr=True):
|
|
"""
|
|
|
|
:param bios_build_dir: Build output directory of Bios
|
|
:param vfr_output_file_path: if not provided then default considered as <xmlcli_build_dir>/Dummy
|
|
:param header_file_path:
|
|
:param knobs_bin_file: bios knob data bin file location
|
|
:param skip_depex: specify whether to skip depex or not
|
|
:param xmlcli_build_dir: Build output directory of XmlCli
|
|
:param process_vfr: Specifies whether to process vfr file or not
|
|
:return:
|
|
"""
|
|
build_dir_x64 = os.path.join(bios_build_dir, "X64")
|
|
if not xmlcli_build_dir:
|
|
xmlcli_build_dir = os.path.join(build_dir_x64, "XmlCliFeaturePkg", "XmlCliCommon")
|
|
if os.path.exists(xmlcli_build_dir):
|
|
print("Create and insert Bios Knobs Data Bin file for XmlCli")
|
|
dummy_dir = make_directory(os.path.join(xmlcli_build_dir, "Dummy"))
|
|
if process_vfr:
|
|
ret_status = clean_vfr_out_file(dummy_dir, input_vfr_directories=input_vfr_directories,
|
|
build_path=build_dir_x64)
|
|
|
|
# remove temp files
|
|
for temp_file in os.listdir(dummy_dir):
|
|
if os.path.splitext(temp_file)[-1] in (".int", ".iout"):
|
|
os.remove(os.path.join(dummy_dir, temp_file))
|
|
|
|
parse_setup_files(vfr_output_file_path=vfr_output_file_path if vfr_output_file_path else dummy_dir,
|
|
header_file_path=header_file_path,
|
|
knobs_bin_file=knobs_bin_file,
|
|
skip_depex=skip_depex)
|
|
|
|
|
|
def parse_setup_files_handler(args):
|
|
print("Parse Setup Files XmlCli Steps with arguments: \n\t{}".format(args))
|
|
|
|
parse_setup_files(vfr_output_file_path=args.vfr_output_file_path,
|
|
header_file_path=args.header_file_path,
|
|
knobs_bin_file=args.knobs_bin_file,
|
|
skip_depex=args.skip_depex)
|
|
|
|
|
|
def clean_vfr_out_file_handler(args):
|
|
print("Clean VFR Out XmlCli Steps with arguments: \n\t{}".format(args))
|
|
|
|
clean_vfr_out_file(vfr_out_path=args.vfr_out_path,
|
|
input_vfr_directories=args.input_vfr_directories,
|
|
build_path=args.build_path)
|
|
|
|
# remove temp files
|
|
for temp_file in os.listdir(args.vfr_out_path):
|
|
if os.path.splitext(temp_file)[-1] in (".int", ".iout"):
|
|
os.remove(os.path.join(args.vfr_out_path, temp_file))
|
|
|
|
|
|
def get_fv_main_component_handler(args):
|
|
print("Get FV main Component XmlCli Steps with arguments: \n\t{}".format(args))
|
|
|
|
guid_str = args.ffs_guid.split(',')
|
|
ffs_guid = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
for index in range(0, len(guid_str)):
|
|
ffs_guid[index] = int(guid_str[index].strip(), 16)
|
|
|
|
get_fv_main_component(bios_rom_file=args.bios_image_file,
|
|
ffs_guid=ffs_guid,
|
|
output_file=args.output_file)
|
|
|
|
|
|
def post_build_handler(args):
|
|
print("Post Build XmlCli Steps with arguments: \n\t{}".format(args))
|
|
|
|
bios_knobs_ui = os.path.join(args.xmlcli_build_dir, "BiosKnobsUISec.ui")
|
|
bios_knobs_data_sec = os.path.join(args.xmlcli_build_dir, "BiosKnobsData.sec")
|
|
bios_knobs_data = os.path.join(args.xmlcli_build_dir, "BiosKnobsData.bin")
|
|
bios_knobs_data_ffs = os.path.join(args.xmlcli_build_dir, "BiosKnobsData.ffs")
|
|
client_bios_fd = os.path.join(args.build_dir, "FV", "ClientBios.fd")
|
|
client_bios_fd_bak = os.path.join(args.build_dir, "FV", "ClientBios.fd.bak")
|
|
xmlcli_client_bios_fd = os.path.join(args.build_dir, "FV", "ClientBios_XmlCli.fd")
|
|
if os.path.exists(client_bios_fd) and not os.path.exists(client_bios_fd_bak):
|
|
shutil.copy(client_bios_fd, client_bios_fd_bak)
|
|
|
|
if not args.stitch_only:
|
|
start_time = time.time()
|
|
post_build(bios_build_dir=args.build_dir,
|
|
xmlcli_build_dir=args.xmlcli_build_dir,
|
|
input_vfr_directories=args.input_vfr_directories,
|
|
process_vfr=args.process_vfr,
|
|
vfr_output_file_path=args.vfr_output_file_path,
|
|
header_file_path=args.header_file_path if args.header_file_path else "all_knobs",
|
|
knobs_bin_file=args.knobs_bin_file if args.knobs_bin_file else bios_knobs_data,
|
|
skip_depex=args.skip_depex)
|
|
print("XmlCli Parsing Time to generate BiosKnobsData.bin = {:.1f} secs".format(time.time() - start_time))
|
|
|
|
# Perform Section/FFS generation
|
|
if args.edk_tools_bin:
|
|
gen_sec_binary = os.path.join(args.edk_tools_bin, GEN_SEC_BIN)
|
|
gen_ffs_binary = os.path.join(args.edk_tools_bin, GEN_FFS_BIN)
|
|
fmmt_binary = os.path.join(args.edk_tools_bin, FMMT_BIN)
|
|
fmmt_input_fd = client_bios_fd if not os.path.exists(client_bios_fd_bak) else client_bios_fd_bak
|
|
|
|
bios_knobs_ui_cmd = [gen_sec_binary, "-s", "EFI_SECTION_USER_INTERFACE", "-n", "XmlCliBiosKnobsData",
|
|
"-o", bios_knobs_ui]
|
|
bios_knobs_data_cmd = [gen_sec_binary, "-s", "EFI_SECTION_RAW",
|
|
"-o", bios_knobs_data_sec, bios_knobs_data]
|
|
bios_knobs_data_ffs_cmd = [gen_ffs_binary, "-t", "EFI_FV_FILETYPE_FREEFORM", "-g", BIOS_KNOBS_BIN_FFS_GUID,
|
|
"-o", bios_knobs_data_ffs,
|
|
"-i", bios_knobs_data_sec, "-i", bios_knobs_ui]
|
|
fmmt_cmd = [fmmt_binary, "-a", fmmt_input_fd,
|
|
BIOS_KNOBS_BIN_FV_GUID, bios_knobs_data_ffs, xmlcli_client_bios_fd]
|
|
|
|
try:
|
|
print(">> Generating Bios Knobs section...\nExecuting: {}".format(bios_knobs_ui_cmd))
|
|
result = subprocess.check_call(bios_knobs_ui_cmd, stderr=subprocess.STDOUT)
|
|
print(result)
|
|
print(">> Generating BiosKnobsData.Bin section...\nExecuting: {}".format(bios_knobs_data_cmd))
|
|
result = subprocess.check_call(bios_knobs_data_cmd, stderr=subprocess.STDOUT)
|
|
print(result)
|
|
print(">> Generating FFS...\nExecuting: {}".format(bios_knobs_data_ffs_cmd))
|
|
result = subprocess.check_call(bios_knobs_data_ffs_cmd, stderr=subprocess.STDOUT)
|
|
print(result)
|
|
print(">> Generating new FD with FMMT...\nExecuting: \n{}".format(" ".join(fmmt_cmd)))
|
|
result = os.popen(" ".join(fmmt_cmd))
|
|
print(result.read())
|
|
except Exception as e:
|
|
print("Exception in subprocess call: {}!!\n".format(e))
|
|
|
|
if not os.path.exists(xmlcli_client_bios_fd):
|
|
print("!!! ERROR:Build Fail !!!")
|
|
print("*** {} does not exist. ***".format(xmlcli_client_bios_fd))
|
|
print("-- FMMT insertion process may have failed, please check logs above --")
|
|
else:
|
|
shutil.copy(xmlcli_client_bios_fd, client_bios_fd)
|
|
print("==== {} File Inserted =====".format(bios_knobs_data))
|
|
|
|
|
|
def main():
|
|
"""Entrypoint method for Parsing setup knobs
|
|
|
|
The file accepts commandline argument:
|
|
argument 1:
|
|
post_build - Build the XmlCli Process from python file itself
|
|
cleanout - Clean All Output files
|
|
getfvmaincmp - Get FV Main component for given FFS Guid
|
|
(otherwise) -
|
|
"""
|
|
print("XmlCli ParseSetup Version {}".format(__version__))
|
|
|
|
arg_parser = argparse.ArgumentParser("XmlCli ParseSetup v{}".format(__version__),
|
|
description="XmlCli Post Build Steps")
|
|
subparsers = arg_parser.add_subparsers()
|
|
|
|
# Post Build
|
|
post_build_parser = subparsers.add_parser("post_build", help="Perform Complete Post Build steps")
|
|
post_build_parser.add_argument("-b", "--build_dir",
|
|
required=True, type=str,
|
|
help="Enter BIOS Build directory where output of all files are generated",
|
|
)
|
|
post_build_parser.add_argument("-xb", "--xmlcli_build_dir",
|
|
required=True, type=str,
|
|
help="Enter Build directory where XmlCli output is generated",
|
|
)
|
|
post_build_parser.add_argument("-iv", "--input_vfr_directories",
|
|
required=False, type=str, nargs="*",
|
|
help="zero or more vfr files",
|
|
)
|
|
post_build_parser.add_argument("-pv", "--process_vfr",
|
|
required=False, type=bool, default=True,
|
|
help="Enter boolean value whether to process vfr file or not. (Default is True)",
|
|
)
|
|
post_build_parser.add_argument("-ov", "--vfr_output_file_path",
|
|
required=False, type=str,
|
|
help="Specify VFR output file location",
|
|
)
|
|
post_build_parser.add_argument("-oh", "--header_file_path",
|
|
required=False, type=str,
|
|
help="Specify output header file location",
|
|
)
|
|
post_build_parser.add_argument("-ob", "--knobs_bin_file",
|
|
required=False, type=str,
|
|
help="Specify output header file location",
|
|
)
|
|
post_build_parser.add_argument("-sd", "--skip_depex",
|
|
required=False, type=bool, default=False,
|
|
help="Specify whether to Skip DEPEX check or not",
|
|
)
|
|
post_build_parser.add_argument("-st", "--stitch_only",
|
|
required=False, type=bool, default=False,
|
|
help="Specify whether to Stitch fd only from already generated bin file or not",
|
|
)
|
|
post_build_parser.add_argument("-edk", "--edk_tools_bin",
|
|
required=False, type=str,
|
|
help="Edk Tools Binaries location",
|
|
)
|
|
post_build_parser.set_defaults(func=post_build_handler)
|
|
|
|
# FV Main Component
|
|
fv_component_parser = subparsers.add_parser("get_fv_main_cmp", help="Perform Complete Post Build steps")
|
|
fv_component_parser.add_argument("-ib", "--bios_image_file",
|
|
required=True, type=str,
|
|
help="BIOS Image file",
|
|
)
|
|
fv_component_parser.add_argument("-fg", "--ffs_guid",
|
|
required=True, type=str,
|
|
help="FFS Guid",
|
|
)
|
|
fv_component_parser.add_argument("-o", "--output_file",
|
|
required=False, type=str,
|
|
help="Output file location",
|
|
)
|
|
fv_component_parser.set_defaults(func=get_fv_main_component_handler)
|
|
|
|
# Parse Setup Files Only
|
|
parse_setup_parser = subparsers.add_parser("parse_setup", help="Perform Parsing only setup files")
|
|
parse_setup_parser.add_argument("-ov", "--vfr_output_file_path",
|
|
required=True, type=str,
|
|
help="Output Vfr path",
|
|
)
|
|
parse_setup_parser.add_argument("-oh", "--header_file_path",
|
|
required=False, type=str,
|
|
help="Specify output header file location",
|
|
)
|
|
parse_setup_parser.add_argument("-ob", "--knobs_bin_file",
|
|
required=True, type=str,
|
|
help="Output Path for generating Bios Knobs Binary",
|
|
)
|
|
parse_setup_parser.add_argument("-sd", "--skip_depex",
|
|
required=False, type=bool, default=False,
|
|
help="Specify whether to Skip DEPEX check or not",
|
|
)
|
|
parse_setup_parser.set_defaults(func=parse_setup_files_handler)
|
|
|
|
# Clean Out File
|
|
clean_out_parser = subparsers.add_parser("clean_out", help="Perform Complete Post Build steps")
|
|
clean_out_parser.add_argument("-ov", "--vfr_out_path",
|
|
required=True, type=str,
|
|
help="Output Vfr path",
|
|
)
|
|
clean_out_parser.add_argument("-iv", "--input_vfr_directories",
|
|
required=False, type=str, nargs="*",
|
|
help="zero or more vfr files",
|
|
)
|
|
clean_out_parser.add_argument("-ob", "--build_path",
|
|
required=True, type=str,
|
|
help="Output Build Path",
|
|
)
|
|
clean_out_parser.set_defaults(func=clean_vfr_out_file_handler)
|
|
|
|
start_time = time.time()
|
|
|
|
args = arg_parser.parse_args()
|
|
args.func(args)
|
|
|
|
print("XmlCli Overall Parsing Time = %.1f secs" % (time.time() - start_time))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|