public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Chiu, Chasel" <chasel.chiu@intel.com>
To: "Loo, Tung Lun" <tung.lun.loo@intel.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Loo, Tung Lun" <tung.lun.loo@intel.com>,
	"Ma, Maurice" <maurice.ma@intel.com>,
	"Desimone, Nathaniel L" <nathaniel.l.desimone@intel.com>,
	"Zeng, Star" <star.zeng@intel.com>
Subject: Re: [PATCH v2] IntelFsp2Pkg: Add YAML file generation support
Date: Fri, 5 Feb 2021 02:09:41 +0000	[thread overview]
Message-ID: <SN6PR11MB2814F9C03DFE3716DE9598C4E6B29@SN6PR11MB2814.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20210204035953.1123-1-tung.lun.loo@intel.com>


Reviewed-by: Chasel Chiu <chasel.chiu@intel.com>


> -----Original Message-----
> From: Loo Tung Lun <tung.lun.loo@intel.com>
> Sent: Thursday, February 4, 2021 12:00 PM
> To: devel@edk2.groups.io
> Cc: Loo, Tung Lun <tung.lun.loo@intel.com>; Ma, Maurice
> <maurice.ma@intel.com>; Desimone, Nathaniel L
> <nathaniel.l.desimone@intel.com>; Zeng, Star <star.zeng@intel.com>; Chiu,
> Chasel <chasel.chiu@intel.com>
> Subject: [PATCH v2] IntelFsp2Pkg: Add YAML file generation support
> 
> Add support for YAML format file generation in addition
> to current BSF structure. Configuration of YAML format
> output will be supported by an open source ConfigEditor.
> 
> Reference to YAML code, test and ConfigEditor is at
> https://github.com/joshloo/fsp_yaml_cfg/tree/master/Tools
> 
> A unit test is also added in Tests folder. This test compares
> the generated yaml file against the expected output to know
> if it is constructing the yaml data structure as expected.
> 
> Cc: Maurice Ma <maurice.ma@intel.com>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Chasel Chiu <chasel.chiu@intel.com>
> Signed-off-by: Loo Tung Lun <tung.lun.loo@intel.com>
> ---
>  IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py                       | 875
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++
>  IntelFsp2Pkg/Tools/GenCfgOpt.py                            | 470
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++------------------------------------------------------------------------------
> ------------------------------------------------------
>  IntelFsp2Pkg/Tools/Tests/ExpectedFspUpd.h                  |  16 ++++++++++++++++
>  IntelFsp2Pkg/Tools/Tests/ExpectedFspmUpd.h                 |  75
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++
>  IntelFsp2Pkg/Tools/Tests/ExpectedFspsUpd.h                 |  69
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++
>  IntelFsp2Pkg/Tools/Tests/ExpectedFsptUpd.h                 |  87
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++
>  IntelFsp2Pkg/Tools/Tests/ExpectedOutput.bsf                |  88
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++
>  IntelFsp2Pkg/Tools/Tests/ExpectedOutput.yaml               | 270
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++
>  IntelFsp2Pkg/Tools/Tests/QemuFspPkg.dsc                    | 469
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++
>  IntelFsp2Pkg/Tools/Tests/test_yaml.py                      |  96
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++
>  IntelFsp2Pkg/Tools/UserManuals/FspDscBsf2YamlUserManual.md |  39
> +++++++++++++++++++++++++++++++++++++++
>  11 files changed, 2422 insertions(+), 132 deletions(-)
> 
> diff --git a/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py
> b/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py
> new file mode 100644
> index 0000000000..2a2ee72ac2
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py
> @@ -0,0 +1,875 @@
> +#!/usr/bin/env python
> 
> +## @ FspDscBsf2Yaml.py
> 
> +# This script convert DSC or BSF format file into YAML format
> 
> +#
> 
> +# Copyright(c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +import os
> 
> +import re
> 
> +import sys
> 
> +from datetime import date
> 
> +from collections import OrderedDict
> 
> +from functools import reduce
> 
> +
> 
> +from GenCfgOpt import CGenCfgOpt
> 
> +
> 
> +__copyright_tmp__ = """## @file
> 
> +#
> 
> +#  YAML CFGDATA %s File.
> 
> +#
> 
> +#  Copyright(c) %4d, Intel Corporation. All rights reserved.<BR>
> 
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +"""
> 
> +
> 
> +__copyright_dsc__ = """## @file
> 
> +#
> 
> +#  Copyright (c) %04d, Intel Corporation. All rights reserved.<BR>
> 
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +[PcdsDynamicVpd.Upd]
> 
> +  #
> 
> +  # Global definitions in BSF
> 
> +  # !BSF BLOCK:{NAME:"FSP UPD Configuration", VER:"0.1"}
> 
> +  #
> 
> +
> 
> +"""
> 
> +
> 
> +
> 
> +def Bytes2Val(Bytes):
> 
> +    return reduce(lambda x, y: (x << 8) | y, Bytes[::-1])
> 
> +
> 
> +
> 
> +class CFspBsf2Dsc:
> 
> +
> 
> +    def __init__(self, bsf_file):
> 
> +        self.cfg_list = CFspBsf2Dsc.parse_bsf(bsf_file)
> 
> +
> 
> +    def get_dsc_lines(self):
> 
> +        return CFspBsf2Dsc.generate_dsc(self.cfg_list)
> 
> +
> 
> +    def save_dsc(self, dsc_file):
> 
> +        return CFspBsf2Dsc.generate_dsc(self.cfg_list, dsc_file)
> 
> +
> 
> +    @staticmethod
> 
> +    def parse_bsf(bsf_file):
> 
> +
> 
> +        fd = open(bsf_file, 'r')
> 
> +        bsf_txt = fd.read()
> 
> +        fd.close()
> 
> +
> 
> +        find_list = []
> 
> +        regex = re.compile(r'\s+Find\s+"(.*?)"(.*?)^\s+\$(.*?)\s+', re.S |
> re.MULTILINE)
> 
> +        for match in regex.finditer(bsf_txt):
> 
> +            find = match.group(1)
> 
> +            name = match.group(3)
> 
> +            if not name.endswith('_Revision'):
> 
> +                raise Exception("Unexpected CFG item following 'Find' !")
> 
> +            find_list.append((name, find))
> 
> +
> 
> +        idx = 0
> 
> +        count = 0
> 
> +        prefix = ''
> 
> +        chk_dict = {}
> 
> +        cfg_list = []
> 
> +        cfg_temp = {'find': '', 'cname': '', 'length': 0, 'value': '0', 'type': 'Reserved',
> 
> +                    'embed': '', 'page': '', 'option': '', 'instance': 0}
> 
> +        regex =
> re.compile(r'^\s+(\$(.*?)|Skip)\s+(\d+)\s+bytes(\s+\$_DEFAULT_\s+=\s+(.+?))?$',
> 
> +                           re.S | re.MULTILINE)
> 
> +
> 
> +        for match in regex.finditer(bsf_txt):
> 
> +            dlen = int(match.group(3))
> 
> +            if match.group(1) == 'Skip':
> 
> +                key = 'gPlatformFspPkgTokenSpaceGuid_BsfSkip%d' % idx
> 
> +                val = ', '.join(['%02X' % ord(i) for i in '\x00' * dlen])
> 
> +                idx += 1
> 
> +                option = '$SKIP'
> 
> +            else:
> 
> +                key = match.group(2)
> 
> +                val = match.group(5)
> 
> +                option = ''
> 
> +
> 
> +            cfg_item = dict(cfg_temp)
> 
> +            finds = [i for i in find_list if i[0] == key]
> 
> +            if len(finds) > 0:
> 
> +                if count >= 1:
> 
> +                    # Append a dummy one
> 
> +                    cfg_item['cname'] = 'Dummy'
> 
> +                    cfg_list.append(dict(cfg_item))
> 
> +                    cfg_list[-1]['embed'] = '%s:TAG_%03X:END' % (prefix, ord(prefix[-1]))
> 
> +                prefix = finds[0][1]
> 
> +                cfg_item['embed'] = '%s:TAG_%03X:START' % (prefix, ord(prefix[-1]))
> 
> +                cfg_item['find'] = prefix
> 
> +                cfg_item['cname'] = 'Signature'
> 
> +                cfg_item['length'] = len(finds[0][1])
> 
> +                cfg_item['value'] = '0x%X' % Bytes2Val(finds[0][1].encode('UTF-8'))
> 
> +                cfg_list.append(dict(cfg_item))
> 
> +                cfg_item = dict(cfg_temp)
> 
> +                find_list.pop(0)
> 
> +                count = 0
> 
> +
> 
> +            cfg_item['cname'] = key
> 
> +            cfg_item['length'] = dlen
> 
> +            cfg_item['value'] = val
> 
> +            cfg_item['option'] = option
> 
> +
> 
> +            if key not in chk_dict.keys():
> 
> +                chk_dict[key] = 0
> 
> +            else:
> 
> +                chk_dict[key] += 1
> 
> +            cfg_item['instance'] = chk_dict[key]
> 
> +
> 
> +            cfg_list.append(cfg_item)
> 
> +            count += 1
> 
> +
> 
> +        if prefix:
> 
> +            cfg_item = dict(cfg_temp)
> 
> +            cfg_item['cname'] = 'Dummy'
> 
> +            cfg_item['embed'] = '%s:%03X:END' % (prefix, ord(prefix[-1]))
> 
> +            cfg_list.append(cfg_item)
> 
> +
> 
> +        option_dict = {}
> 
> +        selreg = re.compile(r'\s+Selection\s*(.+?)\s*,\s*"(.*?)"$', re.S |
> re.MULTILINE)
> 
> +        regex = re.compile(r'^List\s&(.+?)$(.+?)^EndList$', re.S | re.MULTILINE)
> 
> +        for match in regex.finditer(bsf_txt):
> 
> +            key = match.group(1)
> 
> +            option_dict[key] = []
> 
> +            for select in selreg.finditer(match.group(2)):
> 
> +                option_dict[key].append((int(select.group(1), 0), select.group(2)))
> 
> +
> 
> +        chk_dict = {}
> 
> +        pagereg = re.compile(r'^Page\s"(.*?)"$(.+?)^EndPage$', re.S |
> re.MULTILINE)
> 
> +        for match in pagereg.finditer(bsf_txt):
> 
> +            page = match.group(1)
> 
> +            for line in match.group(2).splitlines():
> 
> +                match = re.match(r'\s+(Combo|EditNum)\s\$(.+?),\s"(.*?)",\s(.+?),$',
> line)
> 
> +                if match:
> 
> +                    cname = match.group(2)
> 
> +                    if cname not in chk_dict.keys():
> 
> +                        chk_dict[cname] = 0
> 
> +                    else:
> 
> +                        chk_dict[cname] += 1
> 
> +                    instance = chk_dict[cname]
> 
> +                    cfg_idxs = [i for i, j in enumerate(cfg_list) if j['cname'] == cname and
> j['instance'] == instance]
> 
> +                    if len(cfg_idxs) != 1:
> 
> +                        raise Exception("Multiple CFG item '%s' found !" % cname)
> 
> +                    cfg_item = cfg_list[cfg_idxs[0]]
> 
> +                    cfg_item['page'] = page
> 
> +                    cfg_item['type'] = match.group(1)
> 
> +                    cfg_item['prompt'] = match.group(3)
> 
> +                    cfg_item['range'] = None
> 
> +                    if cfg_item['type'] == 'Combo':
> 
> +                        cfg_item['option'] = option_dict[match.group(4)[1:]]
> 
> +                    elif cfg_item['type'] == 'EditNum':
> 
> +                        cfg_item['option'] = match.group(4)
> 
> +                match = re.match(r'\s+ Help\s"(.*?)"$', line)
> 
> +                if match:
> 
> +                    cfg_item['help'] = match.group(1)
> 
> +
> 
> +                match = re.match(r'\s+"Valid\srange:\s(.*)"$', line)
> 
> +                if match:
> 
> +                    parts = match.group(1).split()
> 
> +                    cfg_item['option'] = (
> 
> +                        (int(parts[0], 0), int(parts[2], 0), cfg_item['option']))
> 
> +
> 
> +        return cfg_list
> 
> +
> 
> +    @staticmethod
> 
> +    def generate_dsc(option_list, dsc_file=None):
> 
> +        dsc_lines = []
> 
> +        header = '%s' % (__copyright_dsc__ % date.today().year)
> 
> +        dsc_lines.extend(header.splitlines())
> 
> +
> 
> +        pages = []
> 
> +        for cfg_item in option_list:
> 
> +            if cfg_item['page'] and (cfg_item['page'] not in pages):
> 
> +                pages.append(cfg_item['page'])
> 
> +
> 
> +        page_id = 0
> 
> +        for page in pages:
> 
> +            dsc_lines.append('  # !BSF PAGES:{PG%02X::"%s"}' % (page_id, page))
> 
> +            page_id += 1
> 
> +        dsc_lines.append('')
> 
> +
> 
> +        last_page = ''
> 
> +        for option in option_list:
> 
> +            dsc_lines.append('')
> 
> +            default = option['value']
> 
> +            pos = option['cname'].find('_')
> 
> +            name = option['cname'][pos + 1:]
> 
> +
> 
> +            if option['find']:
> 
> +                dsc_lines.append('  # !BSF FIND:{%s}' % option['find'])
> 
> +                dsc_lines.append('')
> 
> +
> 
> +            if option['instance'] > 0:
> 
> +                name = name + '_%s' % option['instance']
> 
> +
> 
> +            if option['embed']:
> 
> +                dsc_lines.append('  # !HDR EMBED:{%s}' % option['embed'])
> 
> +
> 
> +            if option['type'] == 'Reserved':
> 
> +                dsc_lines.append('  # !BSF NAME:{Reserved} TYPE:{Reserved}')
> 
> +                if option['option'] == '$SKIP':
> 
> +                    dsc_lines.append('  # !BSF OPTION:{$SKIP}')
> 
> +            else:
> 
> +                prompt = option['prompt']
> 
> +
> 
> +                if last_page != option['page']:
> 
> +                    last_page = option['page']
> 
> +                    dsc_lines.append('  # !BSF PAGE:{PG%02X}' %
> (pages.index(option['page'])))
> 
> +
> 
> +                if option['type'] == 'Combo':
> 
> +                    dsc_lines.append('  # !BSF NAME:{%s} TYPE:{%s}' %
> 
> +                                     (prompt, option['type']))
> 
> +                    ops = []
> 
> +                    for val, text in option['option']:
> 
> +                        ops.append('0x%x:%s' % (val, text))
> 
> +                    dsc_lines.append('  # !BSF OPTION:{%s}' % (', '.join(ops)))
> 
> +                elif option['type'] == 'EditNum':
> 
> +                    cfg_len = option['length']
> 
> +                    if ',' in default and cfg_len > 8:
> 
> +                        dsc_lines.append('  # !BSF NAME:{%s} TYPE:{Table}' % (prompt))
> 
> +                        if cfg_len > 16:
> 
> +                            cfg_len = 16
> 
> +                        ops = []
> 
> +                        for i in range(cfg_len):
> 
> +                            ops.append('%X:1:HEX' % i)
> 
> +                        dsc_lines.append('  # !BSF OPTION:{%s}' % (', '.join(ops)))
> 
> +                    else:
> 
> +                        dsc_lines.append(
> 
> +                            '  # !BSF NAME:{%s} TYPE:{%s, %s,(0x%X, 0x%X)}' %
> 
> +                            (prompt, option['type'], option['option'][2],
> 
> +                             option['option'][0], option['option'][1]))
> 
> +                dsc_lines.append('  # !BSF HELP:{%s}' % option['help'])
> 
> +
> 
> +            if ',' in default:
> 
> +                default = '{%s}' % default
> 
> +            dsc_lines.append('  gCfgData.%-30s | * | 0x%04X | %s' %
> 
> +                             (name, option['length'], default))
> 
> +
> 
> +        if dsc_file:
> 
> +            fd = open(dsc_file, 'w')
> 
> +            fd.write('\n'.join(dsc_lines))
> 
> +            fd.close()
> 
> +
> 
> +        return dsc_lines
> 
> +
> 
> +
> 
> +class CFspDsc2Yaml():
> 
> +
> 
> +    def __init__(self):
> 
> +        self._Hdr_key_list = ['EMBED', 'STRUCT']
> 
> +        self._Bsf_key_list = ['NAME', 'HELP', 'TYPE', 'PAGE', 'PAGES', 'OPTION',
> 
> +                              'CONDITION', 'ORDER', 'MARKER', 'SUBT', 'FIELD', 'FIND']
> 
> +        self.gen_cfg_data = None
> 
> +        self.cfg_reg_exp = re.compile(r"^([_a-zA-Z0-9$\(\)]+)\s*\|\s*(0x[0-9A-
> F]+|\*)\s*\|"
> 
> +                                      + r"\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)")
> 
> +        self.bsf_reg_exp = re.compile(r"(%s):{(.+?)}(?:$|\s+)" %
> '|'.join(self._Bsf_key_list))
> 
> +        self.hdr_reg_exp = re.compile(r"(%s):{(.+?)}" % '|'.join(self._Hdr_key_list))
> 
> +        self.prefix = ''
> 
> +        self.unused_idx = 0
> 
> +        self.offset = 0
> 
> +        self.base_offset = 0
> 
> +
> 
> +    def load_config_data_from_dsc(self, file_name):
> 
> +        """
> 
> +        Load and parse a DSC CFGDATA file.
> 
> +        """
> 
> +        gen_cfg_data = CGenCfgOpt('FSP')
> 
> +        if file_name.endswith('.dsc'):
> 
> +            # if gen_cfg_data.ParseDscFileYaml(file_name, '') != 0:
> 
> +            if gen_cfg_data.ParseDscFile(file_name, '') != 0:
> 
> +                raise Exception('DSC file parsing error !')
> 
> +            if gen_cfg_data.CreateVarDict() != 0:
> 
> +                raise Exception('DSC variable creation error !')
> 
> +        else:
> 
> +            raise Exception('Unsupported file "%s" !' % file_name)
> 
> +        gen_cfg_data.UpdateDefaultValue()
> 
> +        self.gen_cfg_data = gen_cfg_data
> 
> +
> 
> +    def print_dsc_line(self):
> 
> +        """
> 
> +        Debug function to print all DSC lines.
> 
> +        """
> 
> +        for line in self.gen_cfg_data._DscLines:
> 
> +            print(line)
> 
> +
> 
> +    def format_value(self, field, text, indent=''):
> 
> +        """
> 
> +        Format a CFGDATA item into YAML format.
> 
> +        """
> 
> +        if(not text.startswith('!expand')) and (': ' in text):
> 
> +            tgt = ':' if field == 'option' else '- '
> 
> +            text = text.replace(': ', tgt)
> 
> +        lines = text.splitlines()
> 
> +        if len(lines) == 1 and field != 'help':
> 
> +            return text
> 
> +        else:
> 
> +            return '>\n   ' + '\n   '.join([indent + i.lstrip() for i in lines])
> 
> +
> 
> +    def reformat_pages(self, val):
> 
> +        # Convert XXX:YYY into XXX::YYY format for page definition
> 
> +        parts = val.split(',')
> 
> +        if len(parts) <= 1:
> 
> +            return val
> 
> +
> 
> +        new_val = []
> 
> +        for each in parts:
> 
> +            nodes = each.split(':')
> 
> +            if len(nodes) == 2:
> 
> +                each = '%s::%s' % (nodes[0], nodes[1])
> 
> +            new_val.append(each)
> 
> +        ret = ','.join(new_val)
> 
> +        return ret
> 
> +
> 
> +    def reformat_struct_value(self, utype, val):
> 
> +        # Convert DSC UINT16/32/64 array into new format by
> 
> +        # adding prefix 0:0[WDQ] to provide hint to the array format
> 
> +        if utype in ['UINT16', 'UINT32', 'UINT64']:
> 
> +            if val and val[0] == '{' and val[-1] == '}':
> 
> +                if utype == 'UINT16':
> 
> +                    unit = 'W'
> 
> +                elif utype == 'UINT32':
> 
> +                    unit = 'D'
> 
> +                else:
> 
> +                    unit = 'Q'
> 
> +                val = '{ 0:0%s, %s }' % (unit, val[1:-1])
> 
> +        return val
> 
> +
> 
> +    def process_config(self, cfg):
> 
> +        if 'page' in cfg:
> 
> +            cfg['page'] = self.reformat_pages(cfg['page'])
> 
> +
> 
> +        if 'struct' in cfg:
> 
> +            cfg['value'] = self.reformat_struct_value(cfg['struct'], cfg['value'])
> 
> +
> 
> +    def parse_dsc_line(self, dsc_line, config_dict, init_dict, include):
> 
> +        """
> 
> +        Parse a line in DSC and update the config dictionary accordingly.
> 
> +        """
> 
> +        init_dict.clear()
> 
> +        match = re.match(r'g(CfgData|\w+FspPkgTokenSpaceGuid)\.(.+)', dsc_line)
> 
> +        if match:
> 
> +            match = self.cfg_reg_exp.match(match.group(2))
> 
> +            if not match:
> 
> +                return False
> 
> +            config_dict['cname'] = self.prefix + match.group(1)
> 
> +            value = match.group(4).strip()
> 
> +            length = match.group(3).strip()
> 
> +            config_dict['length'] = length
> 
> +            config_dict['value'] = value
> 
> +            if match.group(2) == '*':
> 
> +                self.offset += int(length, 0)
> 
> +            else:
> 
> +                org_offset = int(match.group(2), 0)
> 
> +                if org_offset == 0:
> 
> +                    self.base_offset = self.offset
> 
> +                offset = org_offset + self.base_offset
> 
> +                if self.offset != offset:
> 
> +                    if offset > self.offset:
> 
> +                        init_dict['padding'] = offset - self.offset
> 
> +                self.offset = offset + int(length, 0)
> 
> +            return True
> 
> +
> 
> +        match = re.match(r"^\s*#\s+!([<>])\s+include\s+(.+)", dsc_line)
> 
> +        if match and len(config_dict) == 0:
> 
> +            # !include should not be inside a config field
> 
> +            # if so, do not convert include into YAML
> 
> +            init_dict = dict(config_dict)
> 
> +            config_dict.clear()
> 
> +            config_dict['cname'] = '$ACTION'
> 
> +            if match.group(1) == '<':
> 
> +                config_dict['include'] = match.group(2)
> 
> +            else:
> 
> +                config_dict['include'] = ''
> 
> +            return True
> 
> +
> 
> +        match = re.match(r"^\s*#\s+(!BSF|!HDR)\s+(.+)", dsc_line)
> 
> +        if not match:
> 
> +            return False
> 
> +
> 
> +        remaining = match.group(2)
> 
> +        if match.group(1) == '!BSF':
> 
> +            result = self.bsf_reg_exp.findall(remaining)
> 
> +            if not result:
> 
> +                return False
> 
> +
> 
> +            for each in result:
> 
> +                key = each[0].lower()
> 
> +                val = each[1]
> 
> +                if key == 'field':
> 
> +                    name = each[1]
> 
> +                    if ':' not in name:
> 
> +                        raise Exception('Incorrect bit field format !')
> 
> +                    parts = name.split(':')
> 
> +                    config_dict['length'] = parts[1]
> 
> +                    config_dict['cname'] = '@' + parts[0]
> 
> +                    return True
> 
> +                elif key in ['pages', 'page', 'find']:
> 
> +                    init_dict = dict(config_dict)
> 
> +                    config_dict.clear()
> 
> +                    config_dict['cname'] = '$ACTION'
> 
> +                    if key == 'find':
> 
> +                        config_dict['find'] = val
> 
> +                    else:
> 
> +                        config_dict['page'] = val
> 
> +                    return True
> 
> +                elif key == 'subt':
> 
> +                    config_dict.clear()
> 
> +                    parts = each[1].split(':')
> 
> +                    tmp_name = parts[0][:-5]
> 
> +                    if tmp_name == 'CFGHDR':
> 
> +                        cfg_tag = '_$FFF_'
> 
> +                        sval = '!expand { %s_TMPL : [ ' % tmp_name + '%s, %s, ' %
> (parts[1], cfg_tag) \
> 
> +                               + ', '.join(parts[2:]) + ' ] }'
> 
> +                    else:
> 
> +                        sval = '!expand { %s_TMPL : [ ' % tmp_name + ', '.join(parts[1:]) +
> ' ] }'
> 
> +                    config_dict.clear()
> 
> +                    config_dict['cname'] = tmp_name
> 
> +                    config_dict['expand'] = sval
> 
> +                    return True
> 
> +                else:
> 
> +                    if key in ['name', 'help', 'option'] and val.startswith('+'):
> 
> +                        val = config_dict[key] + '\n' + val[1:]
> 
> +                    if val.strip() == '':
> 
> +                        val = "''"
> 
> +                    config_dict[key] = val
> 
> +
> 
> +        else:
> 
> +            match = self.hdr_reg_exp.match(remaining)
> 
> +            if not match:
> 
> +                return False
> 
> +            key = match.group(1)
> 
> +            remaining = match.group(2)
> 
> +            if key == 'EMBED':
> 
> +                parts = remaining.split(':')
> 
> +                names = parts[0].split(',')
> 
> +                if parts[-1] == 'END':
> 
> +                    prefix = '>'
> 
> +                else:
> 
> +                    prefix = '<'
> 
> +                skip = False
> 
> +                if parts[1].startswith('TAG_'):
> 
> +                    tag_txt = '%s:%s' % (names[0], parts[1])
> 
> +                else:
> 
> +                    tag_txt = names[0]
> 
> +                    if parts[2] in ['START', 'END']:
> 
> +                        if names[0] == 'PCIE_RP_PIN_CTRL[]':
> 
> +                            skip = True
> 
> +                        else:
> 
> +                            tag_txt = '%s:%s' % (names[0], parts[1])
> 
> +                if not skip:
> 
> +                    config_dict.clear()
> 
> +                    config_dict['cname'] = prefix + tag_txt
> 
> +                    return True
> 
> +
> 
> +            if key == 'STRUCT':
> 
> +                text = remaining.strip()
> 
> +                config_dict[key.lower()] = text
> 
> +
> 
> +        return False
> 
> +
> 
> +    def process_template_lines(self, lines):
> 
> +        """
> 
> +        Process a line in DSC template section.
> 
> +        """
> 
> +        template_name = ''
> 
> +        bsf_temp_dict = OrderedDict()
> 
> +        temp_file_dict = OrderedDict()
> 
> +        include_file = ['.']
> 
> +
> 
> +        for line in lines:
> 
> +            match = re.match(r"^\s*#\s+!([<>])\s+include\s+(.+)", line)
> 
> +            if match:
> 
> +                if match.group(1) == '<':
> 
> +                    include_file.append(match.group(2))
> 
> +                else:
> 
> +                    include_file.pop()
> 
> +
> 
> +            match = re.match(r"^\s*#\s+(!BSF)\s+DEFT:{(.+?):(START|END)}", line)
> 
> +            if match:
> 
> +                if match.group(3) == 'START' and not template_name:
> 
> +                    template_name = match.group(2).strip()
> 
> +                    temp_file_dict[template_name] = list(include_file)
> 
> +                    bsf_temp_dict[template_name] = []
> 
> +                if match.group(3) == 'END' and (template_name ==
> match.group(2).strip()) \
> 
> +                   and template_name:
> 
> +                    template_name = ''
> 
> +            else:
> 
> +                if template_name:
> 
> +                    bsf_temp_dict[template_name].append(line)
> 
> +        return bsf_temp_dict, temp_file_dict
> 
> +
> 
> +    def process_option_lines(self, lines):
> 
> +        """
> 
> +        Process a line in DSC config section.
> 
> +        """
> 
> +        cfgs = []
> 
> +        struct_end = False
> 
> +        config_dict = dict()
> 
> +        init_dict = dict()
> 
> +        include = ['']
> 
> +        for line in lines:
> 
> +            ret = self.parse_dsc_line(line, config_dict, init_dict, include)
> 
> +            if ret:
> 
> +                if 'padding' in init_dict:
> 
> +                    num = init_dict['padding']
> 
> +                    init_dict.clear()
> 
> +                    padding_dict = {}
> 
> +                    cfgs.append(padding_dict)
> 
> +                    padding_dict['cname'] = 'UnusedUpdSpace%d' % self.unused_idx
> 
> +                    padding_dict['length'] = '0x%x' % num
> 
> +                    padding_dict['value'] = '{ 0 }'
> 
> +                    self.unused_idx += 1
> 
> +
> 
> +                if cfgs and cfgs[-1]['cname'][0] != '@' and config_dict['cname'][0] ==
> '@':
> 
> +                    # it is a bit field, mark the previous one as virtual
> 
> +                    cname = cfgs[-1]['cname']
> 
> +                    new_cfg = dict(cfgs[-1])
> 
> +                    new_cfg['cname'] = '@$STRUCT'
> 
> +                    cfgs[-1].clear()
> 
> +                    cfgs[-1]['cname'] = cname
> 
> +                    cfgs.append(new_cfg)
> 
> +
> 
> +                if cfgs and cfgs[-1]['cname'] == 'CFGHDR' and config_dict['cname'][0]
> == '<':
> 
> +                    # swap CfgHeader and the CFG_DATA order
> 
> +                    if ':' in config_dict['cname']:
> 
> +                        # replace the real TAG for CFG_DATA
> 
> +                        cfgs[-1]['expand'] = cfgs[-1]['expand'].replace(
> 
> +                            '_$FFF_', '0x%s' %
> 
> +                            config_dict['cname'].split(':')[1][4:])
> 
> +                    cfgs.insert(-1, config_dict)
> 
> +                else:
> 
> +                    self.process_config(config_dict)
> 
> +                    if struct_end:
> 
> +                        struct_end = False
> 
> +                        cfgs.insert(-1, config_dict)
> 
> +                    else:
> 
> +                        cfgs.append(config_dict)
> 
> +                        if config_dict['cname'][0] == '>':
> 
> +                            struct_end = True
> 
> +
> 
> +                config_dict = dict(init_dict)
> 
> +        return cfgs
> 
> +
> 
> +    def variable_fixup(self, each):
> 
> +        """
> 
> +        Fix up some variable definitions for SBL.
> 
> +        """
> 
> +        key = each
> 
> +        val = self.gen_cfg_data._MacroDict[each]
> 
> +        return key, val
> 
> +
> 
> +    def template_fixup(self, tmp_name, tmp_list):
> 
> +        """
> 
> +        Fix up some special config templates for SBL
> 
> +        """
> 
> +        return
> 
> +
> 
> +    def config_fixup(self, cfg_list):
> 
> +        """
> 
> +        Fix up some special config items for SBL.
> 
> +        """
> 
> +
> 
> +        # Insert FSPT_UPD/FSPM_UPD/FSPS_UPD tag so as to create C strcture
> 
> +        idxs = []
> 
> +        for idx, cfg in enumerate(cfg_list):
> 
> +            if cfg['cname'].startswith('<FSP_UPD_HEADER'):
> 
> +                idxs.append(idx)
> 
> +
> 
> +        if len(idxs) != 3:
> 
> +            return
> 
> +
> 
> +        # Handle insert backwards so that the index does not change in the loop
> 
> +        fsp_comp = 'SMT'
> 
> +        idx_comp = 0
> 
> +        for idx in idxs[::-1]:
> 
> +            # Add current FSP?_UPD start tag
> 
> +            cfgfig_dict = {}
> 
> +            cfgfig_dict['cname'] = '<FSP%s_UPD' % fsp_comp[idx_comp]
> 
> +            cfg_list.insert(idx, cfgfig_dict)
> 
> +            if idx_comp < 2:
> 
> +                # Add previous FSP?_UPD end tag
> 
> +                cfgfig_dict = {}
> 
> +                cfgfig_dict['cname'] = '>FSP%s_UPD' % fsp_comp[idx_comp + 1]
> 
> +                cfg_list.insert(idx, cfgfig_dict)
> 
> +            idx_comp += 1
> 
> +
> 
> +        # Add final FSPS_UPD end tag
> 
> +        cfgfig_dict = {}
> 
> +        cfgfig_dict['cname'] = '>FSP%s_UPD' % fsp_comp[0]
> 
> +        cfg_list.append(cfgfig_dict)
> 
> +
> 
> +        return
> 
> +
> 
> +    def get_section_range(self, section_name):
> 
> +        """
> 
> +        Extract line number range from config file for a given section name.
> 
> +        """
> 
> +        start = -1
> 
> +        end = -1
> 
> +        for idx, line in enumerate(self.gen_cfg_data._DscLines):
> 
> +            if start < 0 and line.startswith('[%s]' % section_name):
> 
> +                start = idx
> 
> +            elif start >= 0 and line.startswith('['):
> 
> +                end = idx
> 
> +                break
> 
> +        if start == -1:
> 
> +            start = 0
> 
> +        if end == -1:
> 
> +            end = len(self.gen_cfg_data._DscLines)
> 
> +        return start, end
> 
> +
> 
> +    def normalize_file_name(self, file, is_temp=False):
> 
> +        """
> 
> +        Normalize file name convention so that it is consistent.
> 
> +        """
> 
> +        if file.endswith('.dsc'):
> 
> +            file = file[:-4] + '.yaml'
> 
> +        dir_name = os.path.dirname(file)
> 
> +        base_name = os.path.basename(file)
> 
> +        if is_temp:
> 
> +            if 'Template_' not in file:
> 
> +                base_name = base_name.replace('Template', 'Template_')
> 
> +        else:
> 
> +            if 'CfgData_' not in file:
> 
> +                base_name = base_name.replace('CfgData', 'CfgData_')
> 
> +        if dir_name:
> 
> +            path = dir_name + '/' + base_name
> 
> +        else:
> 
> +            path = base_name
> 
> +        return path
> 
> +
> 
> +    def output_variable(self):
> 
> +        """
> 
> +        Output variable block into a line list.
> 
> +        """
> 
> +        lines = []
> 
> +        for each in self.gen_cfg_data._MacroDict:
> 
> +            key, value = self.variable_fixup(each)
> 
> +            lines.append('%-30s : %s' % (key, value))
> 
> +        return lines
> 
> +
> 
> +    def output_template(self):
> 
> +        """
> 
> +        Output template block into a line list.
> 
> +        """
> 
> +        self.offset = 0
> 
> +        self.base_offset = 0
> 
> +        start, end = self.get_section_range('PcdsDynamicVpd.Tmp')
> 
> +        bsf_temp_dict, temp_file_dict =
> self.process_template_lines(self.gen_cfg_data._DscLines[start:end])
> 
> +        template_dict = dict()
> 
> +        lines = []
> 
> +        file_lines = {}
> 
> +        last_file = '.'
> 
> +        file_lines[last_file] = []
> 
> +
> 
> +        for tmp_name in temp_file_dict:
> 
> +            temp_file_dict[tmp_name][-1] =
> self.normalize_file_name(temp_file_dict[tmp_name][-1], True)
> 
> +            if len(temp_file_dict[tmp_name]) > 1:
> 
> +                temp_file_dict[tmp_name][-2] =
> self.normalize_file_name(temp_file_dict[tmp_name][-2], True)
> 
> +
> 
> +        for tmp_name in bsf_temp_dict:
> 
> +            file = temp_file_dict[tmp_name][-1]
> 
> +            if last_file != file and len(temp_file_dict[tmp_name]) > 1:
> 
> +                inc_file = temp_file_dict[tmp_name][-2]
> 
> +                file_lines[inc_file].extend(['', '- !include %s' %
> temp_file_dict[tmp_name][-1], ''])
> 
> +            last_file = file
> 
> +            if file not in file_lines:
> 
> +                file_lines[file] = []
> 
> +            lines = file_lines[file]
> 
> +            text = bsf_temp_dict[tmp_name]
> 
> +            tmp_list = self.process_option_lines(text)
> 
> +            self.template_fixup(tmp_name, tmp_list)
> 
> +            template_dict[tmp_name] = tmp_list
> 
> +            lines.append('%s: >' % tmp_name)
> 
> +            lines.extend(self.output_dict(tmp_list, False)['.'])
> 
> +            lines.append('\n')
> 
> +        return file_lines
> 
> +
> 
> +    def output_config(self):
> 
> +        """
> 
> +        Output config block into a line list.
> 
> +        """
> 
> +        self.offset = 0
> 
> +        self.base_offset = 0
> 
> +        start, end = self.get_section_range('PcdsDynamicVpd.Upd')
> 
> +        cfgs = self.process_option_lines(self.gen_cfg_data._DscLines[start:end])
> 
> +        self.config_fixup(cfgs)
> 
> +        file_lines = self.output_dict(cfgs, True)
> 
> +        return file_lines
> 
> +
> 
> +    def output_dict(self, cfgs, is_configs):
> 
> +        """
> 
> +        Output one config item into a line list.
> 
> +        """
> 
> +        file_lines = {}
> 
> +        level = 0
> 
> +        file = '.'
> 
> +        for each in cfgs:
> 
> +            if 'length' in each and int(each['length'], 0) == 0:
> 
> +                continue
> 
> +
> 
> +            if 'include' in each:
> 
> +                if each['include']:
> 
> +                    each['include'] = self.normalize_file_name(each['include'])
> 
> +                    file_lines[file].extend(['', '- !include %s' % each['include'], ''])
> 
> +                    file = each['include']
> 
> +                else:
> 
> +                    file = '.'
> 
> +                continue
> 
> +
> 
> +            if file not in file_lines:
> 
> +                file_lines[file] = []
> 
> +
> 
> +            lines = file_lines[file]
> 
> +            name = each['cname']
> 
> +
> 
> +            prefix = name[0]
> 
> +            if prefix == '<':
> 
> +                level += 1
> 
> +
> 
> +            padding = '  ' * level
> 
> +            if prefix not in '<>@':
> 
> +                padding += '  '
> 
> +            else:
> 
> +                name = name[1:]
> 
> +                if prefix == '@':
> 
> +                    padding += '    '
> 
> +
> 
> +            if ':' in name:
> 
> +                parts = name.split(':')
> 
> +                name = parts[0]
> 
> +
> 
> +            padding = padding[2:] if is_configs else padding
> 
> +
> 
> +            if prefix != '>':
> 
> +                if 'expand' in each:
> 
> +                    lines.append('%s- %s' % (padding, each['expand']))
> 
> +                else:
> 
> +                    lines.append('%s- %-12s :' % (padding, name))
> 
> +
> 
> +            for field in each:
> 
> +                if field in ['cname', 'expand', 'include']:
> 
> +                    continue
> 
> +                value_str = self.format_value(field, each[field], padding + ' ' * 16)
> 
> +                full_line = '  %s  %-12s : %s' % (padding, field, value_str)
> 
> +                lines.extend(full_line.splitlines())
> 
> +
> 
> +            if prefix == '>':
> 
> +                level -= 1
> 
> +                if level == 0:
> 
> +                    lines.append('')
> 
> +
> 
> +        return file_lines
> 
> +
> 
> +
> 
> +def bsf_to_dsc(bsf_file, dsc_file):
> 
> +    fsp_dsc = CFspBsf2Dsc(bsf_file)
> 
> +    dsc_lines = fsp_dsc.get_dsc_lines()
> 
> +    fd = open(dsc_file, 'w')
> 
> +    fd.write('\n'.join(dsc_lines))
> 
> +    fd.close()
> 
> +    return
> 
> +
> 
> +
> 
> +def dsc_to_yaml(dsc_file, yaml_file):
> 
> +    dsc2yaml = CFspDsc2Yaml()
> 
> +    dsc2yaml.load_config_data_from_dsc(dsc_file)
> 
> +
> 
> +    cfgs = {}
> 
> +    for cfg in ['Template', 'Option']:
> 
> +        if cfg == 'Template':
> 
> +            file_lines = dsc2yaml.output_template()
> 
> +        else:
> 
> +            file_lines = dsc2yaml.output_config()
> 
> +        for file in file_lines:
> 
> +            lines = file_lines[file]
> 
> +            if file == '.':
> 
> +                cfgs[cfg] = lines
> 
> +            else:
> 
> +                if('/' in file or '\\' in file):
> 
> +                    continue
> 
> +                file = os.path.basename(file)
> 
> +                fo = open(os.path.join(file), 'w')
> 
> +                fo.write(__copyright_tmp__ % (cfg, date.today().year) + '\n\n')
> 
> +                for line in lines:
> 
> +                    fo.write(line + '\n')
> 
> +                fo.close()
> 
> +
> 
> +    variables = dsc2yaml.output_variable()
> 
> +    fo = open(yaml_file, 'w')
> 
> +    fo.write(__copyright_tmp__ % ('Default', date.today().year))
> 
> +    if len(variables) > 0:
> 
> +        fo.write('\n\nvariable:\n')
> 
> +        for line in variables:
> 
> +            fo.write('  ' + line + '\n')
> 
> +
> 
> +    fo.write('\n\ntemplate:\n')
> 
> +    for line in cfgs['Template']:
> 
> +        fo.write('  ' + line + '\n')
> 
> +
> 
> +    fo.write('\n\nconfigs:\n')
> 
> +    for line in cfgs['Option']:
> 
> +        fo.write('  ' + line + '\n')
> 
> +
> 
> +    fo.close()
> 
> +
> 
> +
> 
> +def get_fsp_name_from_path(bsf_file):
> 
> +    name = ''
> 
> +    parts = bsf_file.split(os.sep)
> 
> +    for part in parts:
> 
> +        if part.endswith('FspBinPkg'):
> 
> +            name = part[:-9]
> 
> +            break
> 
> +    if not name:
> 
> +        raise Exception('Could not get FSP name from file path!')
> 
> +    return name
> 
> +
> 
> +
> 
> +def usage():
> 
> +    print('\n'.join([
> 
> +          "FspDscBsf2Yaml Version 0.10",
> 
> +          "Usage:",
> 
> +          "    FspDscBsf2Yaml  BsfFile|DscFile  YamlFile"
> 
> +          ]))
> 
> +
> 
> +
> 
> +def main():
> 
> +    #
> 
> +    # Parse the options and args
> 
> +    #
> 
> +    argc = len(sys.argv)
> 
> +    if argc < 3:
> 
> +        usage()
> 
> +        return 1
> 
> +
> 
> +    bsf_file = sys.argv[1]
> 
> +    yaml_file = sys.argv[2]
> 
> +    if os.path.isdir(yaml_file):
> 
> +        yaml_file = os.path.join(yaml_file, get_fsp_name_from_path(bsf_file) +
> '.yaml')
> 
> +
> 
> +    if bsf_file.endswith('.dsc'):
> 
> +        dsc_file = bsf_file
> 
> +        bsf_file = ''
> 
> +    else:
> 
> +        dsc_file = os.path.splitext(yaml_file)[0] + '.dsc'
> 
> +        bsf_to_dsc(bsf_file, dsc_file)
> 
> +
> 
> +    dsc_to_yaml(dsc_file, yaml_file)
> 
> +
> 
> +    print("'%s' was created successfully!" % yaml_file)
> 
> +
> 
> +    return 0
> 
> +
> 
> +
> 
> +if __name__ == '__main__':
> 
> +    sys.exit(main())
> 
> diff --git a/IntelFsp2Pkg/Tools/GenCfgOpt.py
> b/IntelFsp2Pkg/Tools/GenCfgOpt.py
> index a0b8bba81e..660824b740 100644
> --- a/IntelFsp2Pkg/Tools/GenCfgOpt.py
> +++ b/IntelFsp2Pkg/Tools/GenCfgOpt.py
> @@ -1,6 +1,6 @@
>  ## @ GenCfgOpt.py
> 
>  #
> 
> -# Copyright (c) 2014 - 2020, Intel Corporation. All rights reserved.<BR>
> 
> +# Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>
> 
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
> 
>  #
> 
>  ##
> 
> @@ -283,10 +283,10 @@ class CLogicalExpression:
>          return Result
> 
> 
> 
>  class CGenCfgOpt:
> 
> -    def __init__(self):
> 
> +    def __init__(self, Mode = ''):
> 
>          self.Debug          = False
> 
>          self.Error          = ''
> 
> -
> 
> +        self.Mode           = Mode
> 
>          self._GlobalDataDef = """
> 
>  GlobalDataDef
> 
>      SKUID = 0, "DEFAULT"
> 
> @@ -300,18 +300,20 @@ List &EN_DIS
>  EndList
> 
> 
> 
>  """
> 
> -
> 
> -        self._BsfKeyList    = ['FIND','NAME','HELP','TYPE','PAGE','OPTION','ORDER']
> 
> +        self._BsfKeyList    = ['FIND','NAME','HELP','TYPE','PAGE', 'PAGES', 'BLOCK',
> 'OPTION','CONDITION','ORDER', 'MARKER', 'SUBT']
> 
>          self._HdrKeyList    = ['HEADER','STRUCT', 'EMBED', 'COMMENT']
> 
>          self._BuidinOption  = {'$EN_DIS' : 'EN_DIS'}
> 
> 
> 
>          self._MacroDict   = {}
> 
> +        self._VarDict     = {}
> 
>          self._PcdsDict    = {}
> 
>          self._CfgBlkDict  = {}
> 
>          self._CfgPageDict = {}
> 
> +        self._BsfTempDict = {}
> 
>          self._CfgItemList = []
> 
> +        self._DscLines    = []
> 
>          self._DscFile     = ''
> 
> -        self._FvDir       = ''
> 
> +
> 
>          self._MapVer      = 0
> 
>          self._DscTime     = 0
> 
> 
> 
> @@ -351,7 +353,7 @@ EndList
>              print ("INFO : Eval Ifdef [%s] : %s" % (Macro, Result))
> 
>          return  Result
> 
> 
> 
> -    def ExpandMacros (self, Input):
> 
> +    def ExpandMacros (self, Input, Preserve = False):
> 
>          Line = Input
> 
>          Match = re.findall("\$\(\w+\)", Input)
> 
>          if Match:
> 
> @@ -362,7 +364,8 @@ EndList
>                else:
> 
>                    if self.Debug:
> 
>                        print ("WARN : %s is not defined" % Each)
> 
> -                  Line = Line.replace(Each, Each[2:-1])
> 
> +                  if not Preserve:
> 
> +                      Line = Line.replace(Each, Each[2:-1])
> 
>          return Line
> 
> 
> 
>      def ExpandPcds (self, Input):
> 
> @@ -386,6 +389,70 @@ EndList
>              print ("INFO : Eval Express [%s] : %s" % (Expr, Result))
> 
>          return Result
> 
> 
> 
> +    def ValueToByteArray (self, ValueStr, Length):
> 
> +        Match = re.match("\{\s*FILE:(.+)\}", ValueStr)
> 
> +        if Match:
> 
> +          FileList = Match.group(1).split(',')
> 
> +          Result  = bytearray()
> 
> +          for File in FileList:
> 
> +            File = File.strip()
> 
> +            BinPath = os.path.join(os.path.dirname(self._DscFile), File)
> 
> +            Result.extend(bytearray(open(BinPath, 'rb').read()))
> 
> +        else:
> 
> +            try:
> 
> +                Result  = bytearray(self.ValueToList(ValueStr, Length))
> 
> +            except ValueError as e:
> 
> +                raise Exception ("Bytes in '%s' must be in range 0~255 !" % ValueStr)
> 
> +        if len(Result) < Length:
> 
> +            Result.extend(b'\x00' * (Length - len(Result)))
> 
> +        elif len(Result) > Length:
> 
> +            raise Exception ("Value '%s' is too big to fit into %d bytes !" % (ValueStr,
> Length))
> 
> +
> 
> +        return Result[:Length]
> 
> +
> 
> +    def ValueToList (self, ValueStr, Length):
> 
> +        if ValueStr[0] == '{':
> 
> +            Result = []
> 
> +            BinList = ValueStr[1:-1].split(',')
> 
> +            InBitField     = False
> 
> +            LastInBitField = False
> 
> +            Value          = 0
> 
> +            BitLen         = 0
> 
> +            for Element in BinList:
> 
> +                InBitField = False
> 
> +                Each = Element.strip()
> 
> +                if len(Each) == 0:
> 
> +                    pass
> 
> +                else:
> 
> +                    if Each[0] in ['"', "'"]:
> 
> +                        Result.extend(list(bytearray(Each[1:-1], 'utf-8')))
> 
> +                    elif ':' in Each:
> 
> +                        Match    = re.match("(.+):(\d+)b", Each)
> 
> +                        if Match is None:
> 
> +                            raise Exception("Invald value list format '%s' !" % Each)
> 
> +                        InBitField = True
> 
> +                        CurrentBitLen = int(Match.group(2))
> 
> +                        CurrentValue  = ((self.EvaluateExpress(Match.group(1)) &
> (1<<CurrentBitLen) - 1)) << BitLen
> 
> +                    else:
> 
> +                        Result.append(self.EvaluateExpress(Each.strip()))
> 
> +                if InBitField:
> 
> +                    Value  += CurrentValue
> 
> +                    BitLen += CurrentBitLen
> 
> +                if LastInBitField and ((not InBitField) or (Element == BinList[-1])):
> 
> +                    if BitLen % 8 != 0:
> 
> +                        raise Exception("Invald bit field length!")
> 
> +                    Result.extend(Val2Bytes(Value, BitLen // 8))
> 
> +                    Value  = 0
> 
> +                    BitLen = 0
> 
> +                LastInBitField = InBitField
> 
> +        elif ValueStr.startswith("'") and ValueStr.endswith("'"):
> 
> +            Result = Str2Bytes (ValueStr, Length)
> 
> +        elif ValueStr.startswith('"') and ValueStr.endswith('"'):
> 
> +            Result = Str2Bytes (ValueStr, Length)
> 
> +        else:
> 
> +            Result = Val2Bytes (self.EvaluateExpress(ValueStr), Length)
> 
> +        return Result
> 
> +
> 
>      def FormatListValue(self, ConfigDict):
> 
>          Struct = ConfigDict['struct']
> 
>          if Struct not in ['UINT8','UINT16','UINT32','UINT64']:
> 
> @@ -424,28 +491,53 @@ EndList
>          self._DscFile     = DscFile
> 
>          self._FvDir       = FvDir
> 
> 
> 
> +        self._DscLines    = []
> 
> +        self._BsfTempDict = {}
> 
> +
> 
>          # Initial DSC time is parent DSC time.
> 
>          self._DscTime     = os.path.getmtime(DscFile)
> 
> 
> 
> +        CfgDict = {}
> 
> +
> 
>          IsDefSect       = False
> 
>          IsPcdSect       = False
> 
>          IsUpdSect       = False
> 
>          IsVpdSect       = False
> 
> +        IsTmpSect       = False
> 
> +
> 
> +        TemplateName    = ''
> 
> 
> 
>          IfStack         = []
> 
>          ElifStack       = []
> 
>          Error           = 0
> 
>          ConfigDict      = {}
> 
> 
> 
> -        DscFd        = open(DscFile, "r")
> 
> -        DscLines     = DscFd.readlines()
> 
> -        DscFd.close()
> 
> +
> 
> +        if type(DscFile) is list:
> 
> +            # it is DSC lines already
> 
> +            DscLines       = DscFile
> 
> +            self._DscFile  = '.'
> 
> +        else:
> 
> +            DscFd        = open(DscFile, "r")
> 
> +            DscLines     = DscFd.readlines()
> 
> +            DscFd.close()
> 
> +            self._DscFile = DscFile
> 
> +
> 
> +        SkipLines = 0
> 
> 
> 
>          MaxAlign = 32   #Default align to 32, but if there are 64 bit unit, align to 64
> 
>          SizeAlign = 0   #record the struct max align
> 
>          Base = 0        #Starting offset of sub-structure.
> 
> +
> 
>          while len(DscLines):
> 
>              DscLine  = DscLines.pop(0).strip()
> 
> +            if SkipLines == 0:
> 
> +              self._DscLines.append (DscLine)
> 
> +            else:
> 
> +              SkipLines = SkipLines - 1
> 
> +            if len(DscLine) == 0:
> 
> +              continue
> 
> +
> 
>              Handle   = False
> 
>              Match    = re.match("^\[(.+)\]", DscLine)
> 
>              if Match is not None:
> 
> @@ -453,11 +545,15 @@ EndList
>                  IsPcdSect = False
> 
>                  IsVpdSect = False
> 
>                  IsUpdSect = False
> 
> -                if  Match.group(1).lower() == "Defines".lower():
> 
> +                IsTmpSect = False
> 
> +                SectionName = Match.group(1).lower()
> 
> +                if  SectionName == "Defines".lower():
> 
>                      IsDefSect = True
> 
> -                if  (Match.group(1).lower() == "PcdsFeatureFlag".lower() or
> Match.group(1).lower() == "PcdsFixedAtBuild".lower()):
> 
> +                if  (SectionName == "PcdsFeatureFlag".lower() or SectionName ==
> "PcdsFixedAtBuild".lower()):
> 
>                      IsPcdSect = True
> 
> -                elif Match.group(1).lower() == "PcdsDynamicVpd.Upd".lower():
> 
> +                elif SectionName == "PcdsDynamicVpd.Tmp".lower():
> 
> +                    IsTmpSect = True
> 
> +                elif SectionName == "PcdsDynamicVpd.Upd".lower():
> 
>                      ConfigDict = {}
> 
>                      ConfigDict['header']  = 'ON'
> 
>                      ConfigDict['region']  = 'UPD'
> 
> @@ -465,90 +561,98 @@ EndList
>                      ConfigDict['page']    = ''
> 
>                      ConfigDict['name']    = ''
> 
>                      ConfigDict['find']    = ''
> 
> +                    ConfigDict['marker']  = ''
> 
>                      ConfigDict['struct']  = ''
> 
>                      ConfigDict['embed']   = ''
> 
>                      ConfigDict['comment'] = ''
> 
>                      ConfigDict['subreg']  = []
> 
> +                    ConfigDict['condition']  = ''
> 
> +                    ConfigDict['option']  = ''
> 
>                      IsUpdSect = True
> 
>                      Offset    = 0
> 
>              else:
> 
> -                if IsDefSect or IsPcdSect or IsUpdSect or IsVpdSect:
> 
> -                    if re.match("^!else($|\s+#.+)", DscLine):
> 
> +                if IsDefSect or IsPcdSect or IsUpdSect or IsVpdSect or IsTmpSect:
> 
> +
> 
> +                    Match = False if DscLine[0] != '!' else True
> 
> +                    if Match:
> 
> +                        Match =
> re.match("^!(else|endif|ifdef|ifndef|if|elseif|include)\s*(.+)?$",
> DscLine.split("#")[0])
> 
> +                    Keyword   = Match.group(1) if Match else ''
> 
> +                    Remaining = Match.group(2) if Match else ''
> 
> +                    Remaining = '' if Remaining is None else Remaining.strip()
> 
> +
> 
> +                    if Keyword in ['if', 'elseif', 'ifdef', 'ifndef', 'include'] and not
> Remaining:
> 
> +                        raise Exception ("ERROR: Expression is expected after '!if'
> or !elseif' for line '%s'" % DscLine)
> 
> +
> 
> +                    if Keyword == 'else':
> 
>                          if IfStack:
> 
>                              IfStack[-1] = not IfStack[-1]
> 
>                          else:
> 
> -                            print("ERROR: No paired '!if' found for '!else' for line '%s'" %
> DscLine)
> 
> -                            raise SystemExit
> 
> -                    elif re.match("^!endif($|\s+#.+)", DscLine):
> 
> +                            raise Exception ("ERROR: No paired '!if' found for '!else' for line
> '%s'" % DscLine)
> 
> +                    elif Keyword == 'endif':
> 
>                          if IfStack:
> 
>                              IfStack.pop()
> 
>                              Level = ElifStack.pop()
> 
>                              if Level > 0:
> 
>                                  del IfStack[-Level:]
> 
>                          else:
> 
> -                            print("ERROR: No paired '!if' found for '!endif' for line '%s'" %
> DscLine)
> 
> -                            raise SystemExit
> 
> -                    else:
> 
> -                        Result = False
> 
> -                        Match = re.match("!(ifdef|ifndef)\s+(.+)", DscLine)
> 
> -                        if Match:
> 
> -                            Result = self.EvaulateIfdef (Match.group(2))
> 
> -                            if Match.group(1) == 'ifndef':
> 
> -                                Result = not Result
> 
> -                            IfStack.append(Result)
> 
> +                            raise Exception ("ERROR: No paired '!if' found for '!endif' for
> line '%s'" % DscLine)
> 
> +                    elif Keyword == 'ifdef' or Keyword == 'ifndef':
> 
> +                        Result = self.EvaulateIfdef (Remaining)
> 
> +                        if Keyword == 'ifndef':
> 
> +                            Result = not Result
> 
> +                        IfStack.append(Result)
> 
> +                        ElifStack.append(0)
> 
> +                    elif Keyword == 'if' or Keyword == 'elseif':
> 
> +                        Result = self.EvaluateExpress(Remaining)
> 
> +                        if Keyword == "if":
> 
>                              ElifStack.append(0)
> 
> +                            IfStack.append(Result)
> 
> +                        else:   #elseif
> 
> +                            if IfStack:
> 
> +                                IfStack[-1] = not IfStack[-1]
> 
> +                                IfStack.append(Result)
> 
> +                                ElifStack[-1] = ElifStack[-1] + 1
> 
> +                            else:
> 
> +                                raise Exception ("ERROR: No paired '!if' found for '!elif' for
> line '%s'" % DscLine)
> 
> +                    else:
> 
> +                        if IfStack:
> 
> +                            Handle = reduce(lambda x,y: x and y, IfStack)
> 
>                          else:
> 
> -                            Match  = re.match("!(if|elseif)\s+(.+)", DscLine.split("#")[0])
> 
> +                            Handle = True
> 
> +                        if Handle:
> 
> +                            Match = re.match("!include\s+(.+)", DscLine)
> 
>                              if Match:
> 
> -                                Result = self.EvaluateExpress(Match.group(2))
> 
> -                                if Match.group(1) == "if":
> 
> -                                    ElifStack.append(0)
> 
> -                                    IfStack.append(Result)
> 
> -                                else:   #elseif
> 
> -                                    if IfStack:
> 
> -                                        IfStack[-1] = not IfStack[-1]
> 
> -                                        IfStack.append(Result)
> 
> -                                        ElifStack[-1] = ElifStack[-1] + 1
> 
> -                                    else:
> 
> -                                        print("ERROR: No paired '!if' found for '!elif' for line '%s'"
> % DscLine)
> 
> -                                        raise SystemExit
> 
> -                            else:
> 
> -                                if IfStack:
> 
> -                                    Handle = reduce(lambda x,y: x and y, IfStack)
> 
> +                                IncludeFilePath = Match.group(1)
> 
> +                                IncludeFilePath = self.ExpandMacros(IncludeFilePath)
> 
> +                                PackagesPath = os.getenv("PACKAGES_PATH")
> 
> +                                if PackagesPath:
> 
> +                                  for PackagePath in PackagesPath.split(os.pathsep):
> 
> +                                      IncludeFilePathAbs =
> os.path.join(os.path.normpath(PackagePath),
> os.path.normpath(IncludeFilePath))
> 
> +                                      if os.path.exists(IncludeFilePathAbs):
> 
> +                                          IncludeDsc  = open(IncludeFilePathAbs, "r")
> 
> +                                          break
> 
>                                  else:
> 
> -                                    Handle = True
> 
> -                                if Handle:
> 
> -                                    Match = re.match("!include\s+(.+)", DscLine)
> 
> -                                    if Match:
> 
> -                                        IncludeFilePath = Match.group(1)
> 
> -                                        IncludeFilePath = self.ExpandMacros(IncludeFilePath)
> 
> -                                        PackagesPath = os.getenv("PACKAGES_PATH")
> 
> -                                        if PackagesPath:
> 
> -                                          for PackagePath in PackagesPath.split(os.pathsep):
> 
> -                                              IncludeFilePathAbs =
> os.path.join(os.path.normpath(PackagePath),
> os.path.normpath(IncludeFilePath))
> 
> -                                              if os.path.exists(IncludeFilePathAbs):
> 
> -                                                  IncludeDsc  = open(IncludeFilePathAbs, "r")
> 
> -                                                  break
> 
> -                                        else:
> 
> -                                          IncludeDsc  = open(IncludeFilePath, "r")
> 
> -                                        if IncludeDsc == None:
> 
> -                                            print("ERROR: Cannot open file '%s'" % IncludeFilePath)
> 
> -                                            raise SystemExit
> 
> -
> 
> -                                        # Update DscTime when newer DSC time found.
> 
> -                                        CurrentDscTime =
> os.path.getmtime(os.path.realpath(IncludeDsc.name))
> 
> -                                        if CurrentDscTime > self._DscTime:
> 
> -                                            self._DscTime = CurrentDscTime
> 
> -
> 
> -                                        NewDscLines = IncludeDsc.readlines()
> 
> -                                        IncludeDsc.close()
> 
> -                                        DscLines = NewDscLines + DscLines
> 
> -                                        Offset = 0
> 
> -                                    else:
> 
> -                                        if DscLine.startswith('!'):
> 
> -                                            print("ERROR: Unrecognized directive for line '%s'" %
> DscLine)
> 
> -                                            raise SystemExit
> 
> +                                  IncludeDsc  = open(IncludeFilePath, "r")
> 
> +                                if IncludeDsc == None:
> 
> +                                    print("ERROR: Cannot open file '%s'" % IncludeFilePath)
> 
> +                                    raise SystemExit
> 
> +
> 
> +                                # Update DscTime when newer DSC time found.
> 
> +                                CurrentDscTime =
> os.path.getmtime(os.path.realpath(IncludeDsc.name))
> 
> +                                if CurrentDscTime > self._DscTime:
> 
> +                                    self._DscTime = CurrentDscTime
> 
> +
> 
> +                                NewDscLines = IncludeDsc.readlines()
> 
> +                                IncludeDsc.close()
> 
> +                                DscLines = NewDscLines + DscLines
> 
> +                                del self._DscLines[-1]
> 
> +                                Offset = 0
> 
> +                            else:
> 
> +                                if DscLine.startswith('!'):
> 
> +                                    print("ERROR: Unrecognized directive for line '%s'" %
> DscLine)
> 
> +                                    raise SystemExit
> 
>              if not Handle:
> 
> +                del self._DscLines[-1]
> 
>                  continue
> 
> 
> 
>              if IsDefSect:
> 
> @@ -556,7 +660,7 @@ EndList
>                  #DEFINE FSP_T_UPD_TOOL_GUID = 34686CA3-34F9-4901-B82A-
> BA630F0714C6
> 
>                  #DEFINE FSP_M_UPD_TOOL_GUID = 39A250DB-E465-4DD1-A2AC-
> E2BD3C0E2385
> 
>                  #DEFINE FSP_S_UPD_TOOL_GUID = CAE3605B-5B34-4C85-B3D7-
> 27D54273C40F
> 
> -                Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([/$()-.\w]+)",
> DscLine)
> 
> +                Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*(.+)", DscLine)
> 
>                  if Match:
> 
>                      self._MacroDict[Match.group(1)] =
> self.ExpandMacros(Match.group(2))
> 
>                      if self.Debug:
> 
> @@ -575,6 +679,23 @@ EndList
>                          if Match:
> 
>                              self._PcdsDict[Match.group(1)] = Match.group(2)
> 
>                          i += 1
> 
> +
> 
> +            elif IsTmpSect:
> 
> +                # !BSF DEFT:{GPIO_TMPL:START}
> 
> +                Match = re.match("^\s*#\s+(!BSF)\s+DEFT:{(.+?):(START|END)}",
> DscLine)
> 
> +                if Match:
> 
> +                    if Match.group(3) == 'START' and not TemplateName:
> 
> +                        TemplateName = Match.group(2).strip()
> 
> +                        self._BsfTempDict[TemplateName] = []
> 
> +                    if Match.group(3) == 'END' and (TemplateName ==
> Match.group(2).strip()) and TemplateName:
> 
> +                        TemplateName = ''
> 
> +                else:
> 
> +                    if TemplateName:
> 
> +                        Match = re.match("^!include\s*(.+)?$", DscLine)
> 
> +                        if Match:
> 
> +                            continue
> 
> +                        self._BsfTempDict[TemplateName].append(DscLine)
> 
> +
> 
>              else:
> 
>                  Match = re.match("^\s*#\s+(!BSF|@Bsf|!HDR)\s+(.+)", DscLine)
> 
>                  if Match:
> 
> @@ -630,9 +751,9 @@ EndList
>                  Match = re.match("^\s*#\s*@ValidRange\s*(.+)\s*\|\s*(.+)\s*-
> \s*(.+)\s*", DscLine)
> 
>                  if Match:
> 
>                      if "0x" in Match.group(2) or "0x" in Match.group(3):
> 
> -                       ConfigDict['type'] = "EditNum, HEX, (%s,%s)" % (Match.group(2),
> Match.group(3))
> 
> +                        ConfigDict['type'] = "EditNum, HEX, (%s,%s)" % (Match.group(2),
> Match.group(3))
> 
>                      else:
> 
> -                       ConfigDict['type'] = "EditNum, DEC, (%s,%s)" % (Match.group(2),
> Match.group(3))
> 
> +                        ConfigDict['type'] = "EditNum, DEC, (%s,%s)" % (Match.group(2),
> Match.group(3))
> 
> 
> 
>                  Match = re.match("^\s*##\s+(.+)", DscLine)
> 
>                  if Match:
> 
> @@ -748,6 +869,7 @@ EndList
>                      ConfigDict['struct'] = ''
> 
>                      ConfigDict['embed']  = ''
> 
>                      ConfigDict['comment'] = ''
> 
> +                    ConfigDict['marker'] = ''
> 
>                      ConfigDict['order']  = -1
> 
>                      ConfigDict['subreg'] = []
> 
>                      ConfigDict['option'] = ''
> 
> @@ -786,9 +908,8 @@ EndList
>          bitsvalue = bitsvalue[::-1]
> 
>          bitslen   = len(bitsvalue)
> 
>          if start > bitslen or end > bitslen:
> 
> -            print ("Invalid bits offset [%d,%d] for %s" % (start, end, subitem['name']))
> 
> -            raise SystemExit
> 
> -        return hex(int(bitsvalue[start:end][::-1], 2))
> 
> +            raise Exception ("Invalid bits offset [%d,%d] %d for %s" % (start, end,
> bitslen, subitem['name']))
> 
> +        return '0x%X' % (int(bitsvalue[start:end][::-1], 2))
> 
> 
> 
>      def UpdateSubRegionDefaultValue (self):
> 
>          Error = 0
> 
> @@ -888,63 +1009,142 @@ EndList
>              TxtFd.close()
> 
>          return 0
> 
> 
> 
> -    def ProcessMultilines (self, String, MaxCharLength):
> 
> -            Multilines = ''
> 
> -            StringLength = len(String)
> 
> -            CurrentStringStart = 0
> 
> -            StringOffset = 0
> 
> -            BreakLineDict = []
> 
> -            if len(String) <= MaxCharLength:
> 
> -                while (StringOffset < StringLength):
> 
> -                    if StringOffset >= 1:
> 
> -                        if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
> 
> -                            BreakLineDict.append (StringOffset + 1)
> 
> -                    StringOffset += 1
> 
> -                if BreakLineDict != []:
> 
> -                    for Each in BreakLineDict:
> 
> -                        Multilines += "  %s\n" % String[CurrentStringStart:Each].lstrip()
> 
> -                        CurrentStringStart = Each
> 
> -                    if StringLength - CurrentStringStart > 0:
> 
> -                        Multilines += "  %s\n" % String[CurrentStringStart:].lstrip()
> 
> +    def CreateVarDict (self):
> 
> +        Error = 0
> 
> +        self._VarDict = {}
> 
> +        if len(self._CfgItemList) > 0:
> 
> +            Item = self._CfgItemList[-1]
> 
> +            self._VarDict['_LENGTH_'] = '%d' % (Item['offset'] + Item['length'])
> 
> +        for Item in self._CfgItemList:
> 
> +            Embed = Item['embed']
> 
> +            Match = re.match("^(\w+):(\w+):(START|END)", Embed)
> 
> +            if Match:
> 
> +                StructName = Match.group(1)
> 
> +                VarName = '_%s_%s_' % (Match.group(3), StructName)
> 
> +                if Match.group(3) == 'END':
> 
> +                    self._VarDict[VarName] = Item['offset'] + Item['length']
> 
> +                    self._VarDict['_LENGTH_%s_' % StructName] = \
> 
> +                        self._VarDict['_END_%s_' % StructName] -
> self._VarDict['_START_%s_' % StructName]
> 
> +                    if Match.group(2).startswith('TAG_'):
> 
> +                        if (self.Mode != 'FSP') and (self._VarDict['_LENGTH_%s_' %
> StructName] % 4):
> 
> +                            raise Exception("Size of structure '%s' is %d, not DWORD
> aligned !" % (StructName, self._VarDict['_LENGTH_%s_' % StructName]))
> 
> +                        self._VarDict['_TAG_%s_' % StructName] = int
> (Match.group(2)[4:], 16) & 0xFFF
> 
>                  else:
> 
> -                    Multilines = "  %s\n" % String
> 
> +                    self._VarDict[VarName] = Item['offset']
> 
> +            if Item['marker']:
> 
> +                self._VarDict['_OFFSET_%s_' % Item['marker'].strip()] = Item['offset']
> 
> +        return Error
> 
> +
> 
> +    def UpdateBsfBitUnit (self, Item):
> 
> +        BitTotal  = 0
> 
> +        BitOffset = 0
> 
> +        StartIdx  = 0
> 
> +        Unit      = None
> 
> +        UnitDec   = {1:'BYTE', 2:'WORD', 4:'DWORD', 8:'QWORD'}
> 
> +        for Idx, SubItem in enumerate(Item['subreg']):
> 
> +            if Unit is None:
> 
> +                Unit  = SubItem['bitunit']
> 
> +            BitLength = SubItem['bitlength']
> 
> +            BitTotal  += BitLength
> 
> +            BitOffset += BitLength
> 
> +
> 
> +            if BitOffset > 64 or BitOffset > Unit * 8:
> 
> +                break
> 
> +
> 
> +            if BitOffset == Unit * 8:
> 
> +                for SubIdx in range (StartIdx, Idx + 1):
> 
> +                    Item['subreg'][SubIdx]['bitunit'] = Unit
> 
> +                BitOffset = 0
> 
> +                StartIdx  = Idx + 1
> 
> +                Unit      = None
> 
> +
> 
> +        if BitOffset > 0:
> 
> +            raise Exception ("Bit fields cannot fit into %s for '%s.%s' !" %
> (UnitDec[Unit], Item['cname'], SubItem['cname']))
> 
> +
> 
> +        ExpectedTotal = Item['length'] * 8
> 
> +        if Item['length'] * 8 != BitTotal:
> 
> +            raise Exception ("Bit fields total length (%d) does not match length (%d)
> of '%s' !" % (BitTotal, ExpectedTotal, Item['cname']))
> 
> +
> 
> +    def UpdateDefaultValue (self):
> 
> +        Error = 0
> 
> +        for Idx, Item in enumerate(self._CfgItemList):
> 
> +            if len(Item['subreg']) == 0:
> 
> +                Value = Item['value']
> 
> +                if (len(Value) > 0) and (Value[0] == '{' or Value[0] == "'" or Value[0] ==
> '"'):
> 
> +                    # {XXX} or 'XXX' strings
> 
> +                    self.FormatListValue(self._CfgItemList[Idx])
> 
> +                else:
> 
> +                  Match = re.match("(0x[0-9a-fA-F]+|[0-9]+)", Value)
> 
> +                  if not Match:
> 
> +                    NumValue = self.EvaluateExpress (Value)
> 
> +                    Item['value'] = '0x%X' % NumValue
> 
>              else:
> 
> -                NewLineStart = 0
> 
> -                NewLineCount = 0
> 
> -                FoundSpaceChar = False
> 
> -                while (StringOffset < StringLength):
> 
> -                    if StringOffset >= 1:
> 
> -                        if NewLineCount >= MaxCharLength - 1:
> 
> -                            if String[StringOffset] == ' ' and StringLength - StringOffset > 10:
> 
> -                                BreakLineDict.append (NewLineStart + NewLineCount)
> 
> -                                NewLineStart = NewLineStart + NewLineCount
> 
> -                                NewLineCount = 0
> 
> -                                FoundSpaceChar = True
> 
> -                            elif StringOffset == StringLength - 1 and FoundSpaceChar ==
> False:
> 
> -                                BreakLineDict.append (0)
> 
> -                        if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
> 
> -                            BreakLineDict.append (StringOffset + 1)
> 
> -                            NewLineStart = StringOffset + 1
> 
> +                ValArray = self.ValueToByteArray (Item['value'], Item['length'])
> 
> +                for SubItem in Item['subreg']:
> 
> +                    SubItem['value']   = self.GetBsfBitFields(SubItem, ValArray)
> 
> +                self.UpdateBsfBitUnit (Item)
> 
> +        return Error
> 
> +
> 
> +    def ProcessMultilines (self, String, MaxCharLength):
> 
> +        Multilines = ''
> 
> +        StringLength = len(String)
> 
> +        CurrentStringStart = 0
> 
> +        StringOffset = 0
> 
> +        BreakLineDict = []
> 
> +        if len(String) <= MaxCharLength:
> 
> +            while (StringOffset < StringLength):
> 
> +                if StringOffset >= 1:
> 
> +                    if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
> 
> +                        BreakLineDict.append (StringOffset + 1)
> 
> +                StringOffset += 1
> 
> +            if BreakLineDict != []:
> 
> +                for Each in BreakLineDict:
> 
> +                    Multilines += "  %s\n" % String[CurrentStringStart:Each].lstrip()
> 
> +                    CurrentStringStart = Each
> 
> +                if StringLength - CurrentStringStart > 0:
> 
> +                    Multilines += "  %s\n" % String[CurrentStringStart:].lstrip()
> 
> +            else:
> 
> +                Multilines = "  %s\n" % String
> 
> +        else:
> 
> +            NewLineStart = 0
> 
> +            NewLineCount = 0
> 
> +            FoundSpaceChar = False
> 
> +            while (StringOffset < StringLength):
> 
> +                if StringOffset >= 1:
> 
> +                    if NewLineCount >= MaxCharLength - 1:
> 
> +                        if String[StringOffset] == ' ' and StringLength - StringOffset > 10:
> 
> +                            BreakLineDict.append (NewLineStart + NewLineCount)
> 
> +                            NewLineStart = NewLineStart + NewLineCount
> 
>                              NewLineCount = 0
> 
> -                    StringOffset += 1
> 
> -                    NewLineCount += 1
> 
> -                if BreakLineDict != []:
> 
> -                    BreakLineDict.sort ()
> 
> -                    for Each in BreakLineDict:
> 
> -                        if Each > 0:
> 
> -                            Multilines += "  %s\n" % String[CurrentStringStart:Each].lstrip()
> 
> -                        CurrentStringStart = Each
> 
> -                    if StringLength - CurrentStringStart > 0:
> 
> -                        Multilines += "  %s\n" % String[CurrentStringStart:].lstrip()
> 
> -            return Multilines
> 
> -
> 
> -    def CreateField (self, Item, Name, Length, Offset, Struct, BsfName, Help,
> Option):
> 
> +                            FoundSpaceChar = True
> 
> +                        elif StringOffset == StringLength - 1 and FoundSpaceChar == False:
> 
> +                            BreakLineDict.append (0)
> 
> +                    if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
> 
> +                        BreakLineDict.append (StringOffset + 1)
> 
> +                        NewLineStart = StringOffset + 1
> 
> +                        NewLineCount = 0
> 
> +                StringOffset += 1
> 
> +                NewLineCount += 1
> 
> +            if BreakLineDict != []:
> 
> +                BreakLineDict.sort ()
> 
> +                for Each in BreakLineDict:
> 
> +                    if Each > 0:
> 
> +                        Multilines += "  %s\n" % String[CurrentStringStart:Each].lstrip()
> 
> +                    CurrentStringStart = Each
> 
> +                if StringLength - CurrentStringStart > 0:
> 
> +                    Multilines += "  %s\n" % String[CurrentStringStart:].lstrip()
> 
> +        return Multilines
> 
> +
> 
> +    def CreateField (self, Item, Name, Length, Offset, Struct, BsfName, Help,
> Option, BitsLength = None):
> 
>          PosName    = 28
> 
>          PosComment = 30
> 
>          NameLine=''
> 
>          HelpLine=''
> 
>          OptionLine=''
> 
> 
> 
> +        if Length == 0 and Name == 'Dummy':
> 
> +            return '\n'
> 
> +
> 
>          IsArray = False
> 
>          if Length in [1,2,4,8]:
> 
>              Type = "UINT%d" % (Length * 8)
> 
> @@ -992,7 +1192,12 @@ EndList
>          else:
> 
>              OffsetStr = '0x%04X' % Offset
> 
> 
> 
> -        return "\n/** Offset %s%s%s%s**/\n  %s%s%s;\n" % (OffsetStr, NameLine,
> HelpLine, OptionLine, Type, ' ' * Space1, Name,)
> 
> +        if BitsLength is None:
> 
> +            BitsLength = ''
> 
> +        else:
> 
> +            BitsLength = ' : %d' % BitsLength
> 
> +
> 
> +        return "\n/** Offset %s%s%s%s**/\n  %s%s%s%s;\n" % (OffsetStr,
> NameLine, HelpLine, OptionLine, Type, ' ' * Space1, Name, BitsLength)
> 
> 
> 
>      def PostProcessBody (self, TextBody):
> 
>          NewTextBody = []
> 
> @@ -1097,6 +1302,7 @@ EndList
>              UpdStructure = ['FSPT_UPD', 'FSPM_UPD', 'FSPS_UPD']
> 
>              for Item in self._CfgItemList:
> 
>                  if Item["cname"] == 'Signature' and Item["value"][0:6] in UpdSignature:
> 
> +                    Item["offset"] = 0 # re-initialize offset to 0 when new UPD structure
> starting
> 
>                      UpdOffsetTable.append (Item["offset"])
> 
> 
> 
>              for UpdIdx in range(len(UpdOffsetTable)):
> 
> diff --git a/IntelFsp2Pkg/Tools/Tests/ExpectedFspUpd.h
> b/IntelFsp2Pkg/Tools/Tests/ExpectedFspUpd.h
> new file mode 100644
> index 0000000000..be2ed8aa99
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/Tests/ExpectedFspUpd.h
> @@ -0,0 +1,16 @@
> +#ifndef __FSPUPD_H__
> 
> +#define __FSPUPD_H__
> 
> +
> 
> +#include <FspEas.h>
> 
> +
> 
> +#pragma pack(1)
> 
> +
> 
> +#define FSPT_UPD_SIGNATURE               0x545F4450554D4551        /*
> 'QEMUPD_T' */
> 
> +
> 
> +#define FSPM_UPD_SIGNATURE               0x4D5F4450554D4551        /*
> 'QEMUPD_M' */
> 
> +
> 
> +#define FSPS_UPD_SIGNATURE               0x535F4450554D4551        /*
> 'QEMUPD_S' */
> 
> +
> 
> +#pragma pack()
> 
> +
> 
> +#endif
> 
> diff --git a/IntelFsp2Pkg/Tools/Tests/ExpectedFspmUpd.h
> b/IntelFsp2Pkg/Tools/Tests/ExpectedFspmUpd.h
> new file mode 100644
> index 0000000000..83fd06ecb4
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/Tests/ExpectedFspmUpd.h
> @@ -0,0 +1,75 @@
> +#ifndef __FSPMUPD_H__
> 
> +#define __FSPMUPD_H__
> 
> +
> 
> +#include <FspUpd.h>
> 
> +
> 
> +#pragma pack(1)
> 
> +
> 
> +
> 
> +/** Fsp M Configuration
> 
> +**/
> 
> +typedef struct {
> 
> +
> 
> +/** Offset 0x00C8 - Debug Serial Port Base address
> 
> +  Debug serial port base address. This option will be used only when the 'Serial
> Port
> 
> +  Debug Device' option is set to 'External Device'. 0x00000000(Default).
> 
> +**/
> 
> +  UINT32                      SerialDebugPortAddress;
> 
> +
> 
> +/** Offset 0x00CC - Debug Serial Port Type
> 
> +  16550 compatible debug serial port resource type. NONE means no serial port
> support.
> 
> +  0x02:MMIO(Default).
> 
> +  0:NONE, 1:I/O, 2:MMIO
> 
> +**/
> 
> +  UINT8                       SerialDebugPortType;
> 
> +
> 
> +/** Offset 0x00CD - Serial Port Debug Device
> 
> +  Select active serial port device for debug. For SOC UART devices,'Debug Serial
> Port
> 
> +  Base' options will be ignored. 0x02:SOC UART2(Default).
> 
> +  0:SOC UART0, 1:SOC UART1, 2:SOC UART2, 3:External Device
> 
> +**/
> 
> +  UINT8                       SerialDebugPortDevice;
> 
> +
> 
> +/** Offset 0x00CE - Debug Serial Port Stride Size
> 
> +  Debug serial port register map stride size in bytes. 0x00:1, 0x02:4(Default).
> 
> +  0:1, 2:4
> 
> +**/
> 
> +  UINT8                       SerialDebugPortStrideSize;
> 
> +
> 
> +/** Offset 0x00CF
> 
> +**/
> 
> +  UINT8                       UnusedUpdSpace2[1];
> 
> +
> 
> +/** Offset 0x00D0
> 
> +**/
> 
> +  UINT8                       ReservedFspmUpd[4];
> 
> +} FSP_M_CONFIG;
> 
> +
> 
> +/** Fsp M UPD Configuration
> 
> +**/
> 
> +typedef struct {
> 
> +
> 
> +/** Offset 0x0000
> 
> +**/
> 
> +  FSP_UPD_HEADER              FspUpdHeader;
> 
> +
> 
> +/** Offset 0x00A8
> 
> +**/
> 
> +  FSPM_ARCH_UPD               FspmArchUpd;
> 
> +
> 
> +/** Offset 0x00C8
> 
> +**/
> 
> +  FSP_M_CONFIG                FspmConfig;
> 
> +
> 
> +/** Offset 0x00D4
> 
> +**/
> 
> +  UINT8                       UnusedUpdSpace3[2];
> 
> +
> 
> +/** Offset 0x00D6
> 
> +**/
> 
> +  UINT16                      UpdTerminator;
> 
> +} FSPM_UPD;
> 
> +
> 
> +#pragma pack()
> 
> +
> 
> +#endif
> 
> diff --git a/IntelFsp2Pkg/Tools/Tests/ExpectedFspsUpd.h
> b/IntelFsp2Pkg/Tools/Tests/ExpectedFspsUpd.h
> new file mode 100644
> index 0000000000..e2bc54a61d
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/Tests/ExpectedFspsUpd.h
> @@ -0,0 +1,69 @@
> +#ifndef __FSPSUPD_H__
> 
> +#define __FSPSUPD_H__
> 
> +
> 
> +#include <FspUpd.h>
> 
> +
> 
> +#pragma pack(1)
> 
> +
> 
> +
> 
> +/** Fsp S Configuration
> 
> +**/
> 
> +typedef struct {
> 
> +
> 
> +/** Offset 0x0118 - BMP Logo Data Size
> 
> +  BMP logo data buffer size. 0x00000000(Default).
> 
> +**/
> 
> +  UINT32                      LogoSize;
> 
> +
> 
> +/** Offset 0x011C - BMP Logo Data Pointer
> 
> +  BMP logo data pointer to a BMP format buffer. 0x00000000(Default).
> 
> +**/
> 
> +  UINT32                      LogoPtr;
> 
> +
> 
> +/** Offset 0x0120 - Graphics Configuration Data Pointer
> 
> +  Graphics configuration data used for initialization. 0x00000000(Default).
> 
> +**/
> 
> +  UINT32                      GraphicsConfigPtr;
> 
> +
> 
> +/** Offset 0x0124 - PCI GFX Temporary MMIO Base
> 
> +  PCI Temporary PCI GFX Base used before full PCI enumeration.
> 0x80000000(Default).
> 
> +**/
> 
> +  UINT32                      PciTempResourceBase;
> 
> +
> 
> +/** Offset 0x0128
> 
> +**/
> 
> +  UINT8                       UnusedUpdSpace1[3];
> 
> +
> 
> +/** Offset 0x012B
> 
> +**/
> 
> +  UINT8                       ReservedFspsUpd;
> 
> +} FSP_S_CONFIG;
> 
> +
> 
> +/** Fsp S UPD Configuration
> 
> +**/
> 
> +typedef struct {
> 
> +
> 
> +/** Offset 0x0000
> 
> +**/
> 
> +  FSP_UPD_HEADER              FspUpdHeader;
> 
> +
> 
> +/** Offset 0x00F8
> 
> +**/
> 
> +  FSPS_ARCH_UPD               FspsArchUpd;
> 
> +
> 
> +/** Offset 0x0118
> 
> +**/
> 
> +  FSP_S_CONFIG                FspsConfig;
> 
> +
> 
> +/** Offset 0x012C
> 
> +**/
> 
> +  UINT8                       UnusedUpdSpace2[2];
> 
> +
> 
> +/** Offset 0x012E
> 
> +**/
> 
> +  UINT16                      UpdTerminator;
> 
> +} FSPS_UPD;
> 
> +
> 
> +#pragma pack()
> 
> +
> 
> +#endif
> 
> diff --git a/IntelFsp2Pkg/Tools/Tests/ExpectedFsptUpd.h
> b/IntelFsp2Pkg/Tools/Tests/ExpectedFsptUpd.h
> new file mode 100644
> index 0000000000..25b8a7d63a
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/Tests/ExpectedFsptUpd.h
> @@ -0,0 +1,87 @@
> +#ifndef __FSPTUPD_H__
> 
> +#define __FSPTUPD_H__
> 
> +
> 
> +#include <FspUpd.h>
> 
> +
> 
> +#pragma pack(1)
> 
> +
> 
> +
> 
> +/** Fsp T Common UPD
> 
> +**/
> 
> +typedef struct {
> 
> +
> 
> +/** Offset 0x0040
> 
> +**/
> 
> +  UINT8                       Revision;
> 
> +
> 
> +/** Offset 0x0041
> 
> +**/
> 
> +  UINT8                       Reserved[3];
> 
> +
> 
> +/** Offset 0x0044
> 
> +**/
> 
> +  UINT32                      MicrocodeRegionBase;
> 
> +
> 
> +/** Offset 0x0048
> 
> +**/
> 
> +  UINT32                      MicrocodeRegionLength;
> 
> +
> 
> +/** Offset 0x004C
> 
> +**/
> 
> +  UINT32                      CodeRegionBase;
> 
> +
> 
> +/** Offset 0x0050
> 
> +**/
> 
> +  UINT32                      CodeRegionLength;
> 
> +
> 
> +/** Offset 0x0054
> 
> +**/
> 
> +  UINT8                       Reserved1[12];
> 
> +} FSPT_COMMON_UPD;
> 
> +
> 
> +/** Fsp T Configuration
> 
> +**/
> 
> +typedef struct {
> 
> +
> 
> +/** Offset 0x0060 - Chicken bytes to test Hex config
> 
> +  This option shows how to present option for 4 bytes data
> 
> +**/
> 
> +  UINT32                      ChickenBytes;
> 
> +
> 
> +/** Offset 0x0064
> 
> +**/
> 
> +  UINT8                       ReservedFsptUpd1[28];
> 
> +} FSP_T_CONFIG;
> 
> +
> 
> +/** Fsp T UPD Configuration
> 
> +**/
> 
> +typedef struct {
> 
> +
> 
> +/** Offset 0x0000
> 
> +**/
> 
> +  FSP_UPD_HEADER              FspUpdHeader;
> 
> +
> 
> +/** Offset 0x0020
> 
> +**/
> 
> +  FSPT_ARCH_UPD               FsptArchUpd;
> 
> +
> 
> +/** Offset 0x0040
> 
> +**/
> 
> +  FSPT_COMMON_UPD             FsptCommonUpd;
> 
> +
> 
> +/** Offset 0x0060
> 
> +**/
> 
> +  FSP_T_CONFIG                FsptConfig;
> 
> +
> 
> +/** Offset 0x0080
> 
> +**/
> 
> +  UINT8                       UnusedUpdSpace0[6];
> 
> +
> 
> +/** Offset 0x0086
> 
> +**/
> 
> +  UINT16                      UpdTerminator;
> 
> +} FSPT_UPD;
> 
> +
> 
> +#pragma pack()
> 
> +
> 
> +#endif
> 
> diff --git a/IntelFsp2Pkg/Tools/Tests/ExpectedOutput.bsf
> b/IntelFsp2Pkg/Tools/Tests/ExpectedOutput.bsf
> new file mode 100644
> index 0000000000..750e1b4faf
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/Tests/ExpectedOutput.bsf
> @@ -0,0 +1,88 @@
> +GlobalDataDef
> 
> +    SKUID = 0, "DEFAULT"
> 
> +EndGlobalData
> 
> +
> 
> +
> 
> +StructDef
> 
> +
> 
> +    Find "QEMUPD_T"
> 
> +        $gQemuFspPkgTokenSpaceGuid_Revision                            1 bytes
> $_DEFAULT_ = 0x01
> 
> +        Skip 87 bytes
> 
> +        $gQemuFspPkgTokenSpaceGuid_ChickenBytes                        4 bytes
> $_DEFAULT_ = 0x00000000
> 
> +
> 
> +    Find "QEMUPD_M"
> 
> +        $gQemuFspPkgTokenSpaceGuid_Revision                            1 bytes
> $_DEFAULT_ = 0x01
> 
> +        Skip 35 bytes
> 
> +        $gQemuFspPkgTokenSpaceGuid_StackBase                           4 bytes
> $_DEFAULT_ = 0x00070000
> 
> +        $gQemuFspPkgTokenSpaceGuid_StackSize                           4 bytes
> $_DEFAULT_ = 0x00010000
> 
> +        $gQemuFspPkgTokenSpaceGuid_BootLoaderTolumSize                 4 bytes
> $_DEFAULT_ = 0x00000000
> 
> +        $gPlatformFspPkgTokenSpaceGuid_Bootmode                        4 bytes
> $_DEFAULT_ = 0x00000000
> 
> +        Skip 8 bytes
> 
> +        $gQemuFspPkgTokenSpaceGuid_SerialDebugPortAddress              4 bytes
> $_DEFAULT_ = 0x00000000
> 
> +        $gQemuFspPkgTokenSpaceGuid_SerialDebugPortType                 1 bytes
> $_DEFAULT_ = 0x02
> 
> +        $gQemuFspPkgTokenSpaceGuid_SerialDebugPortDevice               1 bytes
> $_DEFAULT_ = 0x02
> 
> +        $gQemuFspPkgTokenSpaceGuid_SerialDebugPortStrideSize           1 bytes
> $_DEFAULT_ = 0x02
> 
> +
> 
> +    Find "QEMUPD_S"
> 
> +        $gQemuFspPkgTokenSpaceGuid_Revision                            1 bytes
> $_DEFAULT_ = 0x01
> 
> +        Skip 55 bytes
> 
> +        $gQemuFspPkgTokenSpaceGuid_LogoSize                            4 bytes
> $_DEFAULT_ = 0x00000000
> 
> +        $gQemuFspPkgTokenSpaceGuid_LogoPtr                             4 bytes
> $_DEFAULT_ = 0x00000000
> 
> +        $gQemuFspPkgTokenSpaceGuid_GraphicsConfigPtr                   4 bytes
> $_DEFAULT_ = 0x00000000
> 
> +        $gQemuFspPkgTokenSpaceGuid_PciTempResourceBase                 4 bytes
> $_DEFAULT_ = 0x80000000
> 
> +
> 
> +EndStruct
> 
> +
> 
> +
> 
> +List &EN_DIS
> 
> +    Selection 0x1 , "Enabled"
> 
> +    Selection 0x0 , "Disabled"
> 
> +EndList
> 
> +
> 
> +List &gQemuFspPkgTokenSpaceGuid_SerialDebugPortType
> 
> +    Selection 0 , "NONE"
> 
> +    Selection 1 , "I/O"
> 
> +    Selection 2 , "MMIO"
> 
> +EndList
> 
> +
> 
> +List &gQemuFspPkgTokenSpaceGuid_SerialDebugPortDevice
> 
> +    Selection 0 , "SOC UART0"
> 
> +    Selection 1 , "SOC UART1"
> 
> +    Selection 2 , "SOC UART2"
> 
> +    Selection 3 , "External Device"
> 
> +EndList
> 
> +
> 
> +List &gQemuFspPkgTokenSpaceGuid_SerialDebugPortStrideSize
> 
> +    Selection 0 , "1"
> 
> +    Selection 2 , "4"
> 
> +EndList
> 
> +
> 
> +BeginInfoBlock
> 
> +    PPVer       "0.1"
> 
> +    Description "QEMU Platform"
> 
> +EndInfoBlock
> 
> +
> 
> +Page "FSP T"
> 
> +    EditNum $gQemuFspPkgTokenSpaceGuid_ChickenBytes, "Chicken bytes to
> test Hex config", HEX,
> 
> +        Help "This option shows how to present option for 4 bytes data"
> 
> +             "Valid range: 0x00000000 ~ 0xFFFFFFFF"
> 
> +EndPage
> 
> +
> 
> +Page "FSP MemoryInit Settings"
> 
> +    EditNum $gQemuFspPkgTokenSpaceGuid_SerialDebugPortAddress, "Debug
> Serial Port Base address", HEX,
> 
> +        Help "Debug serial port base address. This option will be used only when
> the 'Serial Port Debug Device' option is set to 'External Device'.
> 0x00000000(Default)."
> 
> +             "Valid range: 0x00000000 ~ 0xFFFFFFFF"
> 
> +    Combo $gQemuFspPkgTokenSpaceGuid_SerialDebugPortType, "Debug Serial
> Port Type", &gQemuFspPkgTokenSpaceGuid_SerialDebugPortType,
> 
> +        Help "16550 compatible debug serial port resource type. NONE means no
> serial port support. 0x02:MMIO(Default)."
> 
> +    Combo $gQemuFspPkgTokenSpaceGuid_SerialDebugPortDevice, "Serial Port
> Debug Device", &gQemuFspPkgTokenSpaceGuid_SerialDebugPortDevice,
> 
> +        Help "Select active serial port device for debug. For SOC UART
> devices,'Debug Serial Port Base' options will be ignored. 0x02:SOC
> UART2(Default)."
> 
> +    Combo $gQemuFspPkgTokenSpaceGuid_SerialDebugPortStrideSize, "Debug
> Serial Port Stride Size",
> &gQemuFspPkgTokenSpaceGuid_SerialDebugPortStrideSize,
> 
> +        Help "Debug serial port register map stride size in bytes. 0x00:1,
> 0x02:4(Default)."
> 
> +EndPage
> 
> +
> 
> +Page "FSP SiliconInit Settings"
> 
> +    EditNum $gQemuFspPkgTokenSpaceGuid_PciTempResourceBase, "PCI GFX
> Temporary MMIO Base", HEX,
> 
> +        Help "PCI Temporary PCI GFX Base used before full PCI enumeration.
> 0x80000000(Default)."
> 
> +             "Valid range: 0x80000000 ~ 0xDFFFFFFF"
> 
> +EndPage
> 
> +
> 
> diff --git a/IntelFsp2Pkg/Tools/Tests/ExpectedOutput.yaml
> b/IntelFsp2Pkg/Tools/Tests/ExpectedOutput.yaml
> new file mode 100644
> index 0000000000..3594b9895e
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/Tests/ExpectedOutput.yaml
> @@ -0,0 +1,270 @@
> +variable:
> 
> +  PLATFORM_NAME                  : QemuFspPkg
> 
> +  PLATFORM_GUID                  : 1BEDB57A-7904-406e-8486-C89FC7FB39EE
> 
> +  PLATFORM_VERSION               : 0.1
> 
> +  DSC_SPECIFICATION              : 0x00010005
> 
> +  OUTPUT_DIRECTORY               : Build/QemuFspPkg
> 
> +  SUPPORTED_ARCHITECTURES        : IA32|X64
> 
> +  BUILD_TARGETS                  : DEBUG|RELEASE
> 
> +  SKUID_IDENTIFIER               : DEFAULT
> 
> +  FLASH_DEFINITION               : QemuFspPkg/QemuFspPkg.fdf
> 
> +  FSP_T_UPD_TOOL_GUID            : 34686CA3-34F9-4901-B82A-BA630F0714C6
> 
> +  FSP_V_UPD_TOOL_GUID            : 4E2F4725-734A-4399-BAF5-B4E16348EB2F
> 
> +  FSP_M_UPD_TOOL_GUID            : 39A250DB-E465-4DD1-A2AC-
> E2BD3C0E2385
> 
> +  FSP_S_UPD_TOOL_GUID            : CAE3605B-5B34-4C85-B3D7-27D54273C40F
> 
> +  FSP_T_UPD_FFS_GUID             : 70BCF6A5-FFB1-47D8-B1AE-EFE5508E23EA
> 
> +  FSP_V_UPD_FFS_GUID             : 0197EF5E-2FFC-4089-8E55-F70400B18146
> 
> +  FSP_M_UPD_FFS_GUID             : D5B86AEA-6AF7-40D4-8014-982301BC3D89
> 
> +  FSP_S_UPD_FFS_GUID             : E3CD9B18-998C-4F76-B65E-98B154E5446F
> 
> +  FSP_PACKAGE                    : QemuFspPkg
> 
> +  FSP_IMAGE_ID                   : 0x245053464D455124  # $QEMFSP$
> 
> +  FSP_IMAGE_REV                  : 0x00001010
> 
> +  CAR_BASE_ADDRESS               : 0x00000000
> 
> +  CAR_REGION_SIZE                : 0x00080000
> 
> +  CAR_BLD_REGION_SIZE            : 0x00070000
> 
> +  CAR_FSP_REGION_SIZE            : 0x00010000
> 
> +  FSP_ARCH                       : X64
> 
> +
> 
> +
> 
> +template:
> 
> +
> 
> +
> 
> +configs:
> 
> +  - $ACTION      :
> 
> +      page         : TMP::"FSP T", MEM::"FSP MemoryInit Settings", SIL::"FSP
> SiliconInit Settings"
> 
> +  - $ACTION      :
> 
> +      find         : QEMUPD_T
> 
> +  - FSPT_UPD     :
> 
> +    - FSP_UPD_HEADER :
> 
> +      - Signature    :
> 
> +          length       : 0x08
> 
> +          value        : 0x545F4450554D4551
> 
> +      - Revision     :
> 
> +          name         : FsptUpdRevision
> 
> +          length       : 0x01
> 
> +          value        : 0x01
> 
> +      - Reserved     :
> 
> +          length       : 0x17
> 
> +          value        : {0x00}
> 
> +    - FSPT_ARCH_UPD :
> 
> +      - Revision     :
> 
> +          length       : 0x01
> 
> +          value        : 0x01
> 
> +      - Reserved     :
> 
> +          length       : 0x03
> 
> +          value        : {0x00}
> 
> +      - Length       :
> 
> +          length       : 0x04
> 
> +          value        : 0x00000020
> 
> +      - FspDebugHandler :
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - Reserved1    :
> 
> +          length       : 0x14
> 
> +          value        : {0x00}
> 
> +    - FSPT_COMMON_UPD :
> 
> +      - Revision     :
> 
> +          length       : 0x01
> 
> +          value        : 0x01
> 
> +      - Reserved     :
> 
> +          length       : 0x03
> 
> +          value        : {0x00}
> 
> +      - MicrocodeRegionBase :
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - MicrocodeRegionLength :
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - CodeRegionBase :
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - CodeRegionLength :
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - Reserved1    :
> 
> +          length       : 0x0C
> 
> +          value        : {0x00}
> 
> +    - FSP_T_CONFIG :
> 
> +      - $ACTION      :
> 
> +          page         : TMP
> 
> +      - ChickenBytes :
> 
> +          name         : Chicken bytes to test Hex config
> 
> +          type         : EditNum, HEX, (0x00000000,0xFFFFFFFF)
> 
> +          help         : >
> 
> +                         This option shows how to present option for 4 bytes data
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - ReservedFsptUpd1 :
> 
> +          length       : 0x1C
> 
> +          value        : {0x00}
> 
> +    - UpdTerminator :
> 
> +        length       : 0x02
> 
> +        value        : 0x55AA
> 
> +    - $ACTION      :
> 
> +        find         : QEMUPD_M
> 
> +
> 
> +  - FSPM_UPD     :
> 
> +    - FSP_UPD_HEADER :
> 
> +      - Signature    :
> 
> +          length       : 0x08
> 
> +          value        : 0x4D5F4450554D4551
> 
> +      - Revision     :
> 
> +          name         : FspmUpdRevision
> 
> +          length       : 0x01
> 
> +          value        : 0x01
> 
> +      - Reserved     :
> 
> +          length       : 0x17
> 
> +          value        : {0x00}
> 
> +    - FSPM_ARCH_UPD :
> 
> +      - Revision     :
> 
> +          length       : 0x01
> 
> +          value        : 0x01
> 
> +      - Reserved     :
> 
> +          length       : 0x03
> 
> +          value        : {0x00}
> 
> +      - NvsBufferPtr :
> 
> +          struct       : VOID*
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - StackBase    :
> 
> +          struct       : VOID*
> 
> +          name         : StackBase
> 
> +          help         : >
> 
> +                         Stack base for FSP use. Default- 0xFEF16000
> 
> +          length       : 0x04
> 
> +          value        : $(CAR_BLD_REGION_SIZE)
> 
> +      - StackSize    :
> 
> +          name         : StackSize
> 
> +          help         : >
> 
> +                         To pass the stack size for FSP use. Bootloader can
> programmatically get the FSP requested StackSize by using the defaults in the
> FSP-M component. This is the minimum stack size expected by this revision of
> FSP. Default- 0x2A000
> 
> +          length       : 0x04
> 
> +          value        : $(CAR_FSP_REGION_SIZE)
> 
> +      - BootLoaderTolumSize :
> 
> +          name         : BootLoaderTolumSize
> 
> +          help         : >
> 
> +                         To pass Bootloader Tolum size.
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - Bootmode     :
> 
> +          name         : Bootmode
> 
> +          help         : >
> 
> +                         To maintain Bootmode details.
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - Reserved1    :
> 
> +          length       : 0x08
> 
> +          value        : {0x00}
> 
> +    - FSP_M_CONFIG :
> 
> +      - $ACTION      :
> 
> +          page         : MEM
> 
> +      - SerialDebugPortAddress :
> 
> +          name         : Debug Serial Port Base address
> 
> +          type         : EditNum, HEX, (0x00000000,0xFFFFFFFF)
> 
> +          help         : >
> 
> +                         Debug serial port base address. This option will be used only
> when the 'Serial Port Debug Device'
> 
> +                         option is set to 'External Device'. 0x00000000(Default).
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - SerialDebugPortType :
> 
> +          name         : Debug Serial Port Type
> 
> +          type         : Combo
> 
> +          option       : 0:NONE, 1:I/O, 2:MMIO
> 
> +          help         : >
> 
> +                         16550 compatible debug serial port resource type. NONE means
> no serial port support. 0x02:MMIO(Default).
> 
> +          length       : 0x01
> 
> +          value        : 0x02
> 
> +      - SerialDebugPortDevice :
> 
> +          name         : Serial Port Debug Device
> 
> +          type         : Combo
> 
> +          option       : 0:SOC UART0, 1:SOC UART1, 2:SOC UART2, 3:External Device
> 
> +          help         : >
> 
> +                         Select active serial port device for debug.
> 
> +                         For SOC UART devices,'Debug Serial Port Base' options will be
> ignored. 0x02:SOC UART2(Default).
> 
> +          length       : 0x01
> 
> +          value        : 0x02
> 
> +      - SerialDebugPortStrideSize :
> 
> +          name         : Debug Serial Port Stride Size
> 
> +          type         : Combo
> 
> +          option       : 0:1, 2:4
> 
> +          help         : >
> 
> +                         Debug serial port register map stride size in bytes. 0x00:1,
> 0x02:4(Default).
> 
> +          length       : 0x01
> 
> +          value        : 0x02
> 
> +      - ReservedFspmUpd :
> 
> +          length       : 0x04
> 
> +          value        : {0x00}
> 
> +    - UpdTerminator :
> 
> +        length       : 0x02
> 
> +        value        : 0x55AA
> 
> +    - $ACTION      :
> 
> +        find         : QEMUPD_S
> 
> +
> 
> +  - FSPS_UPD     :
> 
> +    - FSP_UPD_HEADER :
> 
> +      - Signature    :
> 
> +          length       : 0x08
> 
> +          value        : 0x535F4450554D4551
> 
> +      - Revision     :
> 
> +          name         : FspsUpdRevision
> 
> +          length       : 0x01
> 
> +          value        : 0x01
> 
> +      - Reserved     :
> 
> +          length       : 0x17
> 
> +          value        : {0x00}
> 
> +    - FSPS_ARCH_UPD :
> 
> +      - Revision     :
> 
> +          length       : 0x01
> 
> +          value        : 0x01
> 
> +      - Reserved     :
> 
> +          length       : 0x03
> 
> +          value        : {0x00}
> 
> +      - Length       :
> 
> +          length       : 0x04
> 
> +          value        : 0x00000020
> 
> +      - FspEventHandler :
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - EnableMultiPhaseSiliconInit :
> 
> +          length       : 0x01
> 
> +          value        : 0x00
> 
> +      - Reserved1    :
> 
> +          length       : 0x13
> 
> +          value        : {0x00}
> 
> +    - FSP_S_CONFIG :
> 
> +      - $ACTION      :
> 
> +          page         : SIL
> 
> +      - LogoSize     :
> 
> +          name         : BMP Logo Data Size
> 
> +          type         : Reserved
> 
> +          help         : >
> 
> +                         BMP logo data buffer size. 0x00000000(Default).
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - LogoPtr      :
> 
> +          name         : BMP Logo Data Pointer
> 
> +          type         : Reserved
> 
> +          help         : >
> 
> +                         BMP logo data pointer to a BMP format buffer.
> 0x00000000(Default).
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - GraphicsConfigPtr :
> 
> +          name         : Graphics Configuration Data Pointer
> 
> +          type         : Reserved
> 
> +          help         : >
> 
> +                         Graphics configuration data used for initialization.
> 0x00000000(Default).
> 
> +          length       : 0x04
> 
> +          value        : 0x00000000
> 
> +      - PciTempResourceBase :
> 
> +          name         : PCI GFX Temporary MMIO Base
> 
> +          type         : EditNum, HEX, (0x80000000,0xDFFFFFFF)
> 
> +          help         : >
> 
> +                         PCI Temporary PCI GFX Base used before full PCI enumeration.
> 0x80000000(Default).
> 
> +          length       : 0x04
> 
> +          value        : 0x80000000
> 
> +      - ReservedFspsUpd :
> 
> +          length       : 0x01
> 
> +          value        : 0x00
> 
> +    - UpdTerminator :
> 
> +        length       : 0x02
> 
> +        value        : 0x55AA
> 
> +
> 
> diff --git a/IntelFsp2Pkg/Tools/Tests/QemuFspPkg.dsc
> b/IntelFsp2Pkg/Tools/Tests/QemuFspPkg.dsc
> new file mode 100644
> index 0000000000..af0bd4e717
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/Tests/QemuFspPkg.dsc
> @@ -0,0 +1,469 @@
> +## @file
> 
> +# FSP DSC build file for QEMU platform
> 
> +#
> 
> +# Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +#    This program and the accompanying materials
> 
> +#    are licensed and made available under the terms and conditions of the BSD
> License
> 
> +#    which accompanies this distribution. The full text of the license may be
> found at
> 
> +#    http://opensource.org/licenses/bsd-license.php
> 
> +#
> 
> +#    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> 
> +#    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> 
> +#
> 
> +##
> 
> +
> 
> +################################################################
> ################
> 
> +#
> 
> +# Defines Section - statements that will be processed to create a Makefile.
> 
> +#
> 
> +################################################################
> ################
> 
> +[Defines]
> 
> +  PLATFORM_NAME                  = QemuFspPkg
> 
> +  PLATFORM_GUID                  = 1BEDB57A-7904-406e-8486-C89FC7FB39EE
> 
> +  PLATFORM_VERSION               = 0.1
> 
> +  DSC_SPECIFICATION              = 0x00010005
> 
> +  OUTPUT_DIRECTORY               = Build/QemuFspPkg
> 
> +  SUPPORTED_ARCHITECTURES        = IA32|X64
> 
> +  BUILD_TARGETS                  = DEBUG|RELEASE
> 
> +  SKUID_IDENTIFIER               = DEFAULT
> 
> +  FLASH_DEFINITION               = QemuFspPkg/QemuFspPkg.fdf
> 
> +
> 
> +  #
> 
> +  # UPD tool definition
> 
> +  #
> 
> +  FSP_T_UPD_TOOL_GUID            = 34686CA3-34F9-4901-B82A-BA630F0714C6
> 
> +  FSP_V_UPD_TOOL_GUID            = 4E2F4725-734A-4399-BAF5-B4E16348EB2F
> 
> +  FSP_M_UPD_TOOL_GUID            = 39A250DB-E465-4DD1-A2AC-
> E2BD3C0E2385
> 
> +  FSP_S_UPD_TOOL_GUID            = CAE3605B-5B34-4C85-B3D7-27D54273C40F
> 
> +  FSP_T_UPD_FFS_GUID             = 70BCF6A5-FFB1-47D8-B1AE-EFE5508E23EA
> 
> +  FSP_V_UPD_FFS_GUID             = 0197EF5E-2FFC-4089-8E55-F70400B18146
> 
> +  FSP_M_UPD_FFS_GUID             = D5B86AEA-6AF7-40D4-8014-982301BC3D89
> 
> +  FSP_S_UPD_FFS_GUID             = E3CD9B18-998C-4F76-B65E-98B154E5446F
> 
> +
> 
> +  #
> 
> +  # Set platform specific package/folder name, same as passed from PREBUILD
> script.
> 
> +  # PLATFORM_PACKAGE would be the same as PLATFORM_NAME as well as
> package build folder
> 
> +  # DEFINE only takes effect at R9 DSC and FDF.
> 
> +  #
> 
> +  DEFINE FSP_PACKAGE                     = QemuFspPkg
> 
> +  DEFINE FSP_IMAGE_ID                    = 0x245053464D455124  # $QEMFSP$
> 
> +  DEFINE FSP_IMAGE_REV                   = 0x00001010
> 
> +
> 
> +  DEFINE CAR_BASE_ADDRESS                = 0x00000000
> 
> +  DEFINE CAR_REGION_SIZE                 = 0x00080000
> 
> +  DEFINE CAR_BLD_REGION_SIZE             = 0x00070000
> 
> +  DEFINE CAR_FSP_REGION_SIZE             = 0x00010000
> 
> +
> 
> +  DEFINE FSP_ARCH                        = X64
> 
> +
> 
> +################################################################
> ################
> 
> +#
> 
> +# SKU Identification section - list of all SKU IDs supported by this
> 
> +#                              Platform.
> 
> +#
> 
> +################################################################
> ################
> 
> +[SkuIds]
> 
> +  0|DEFAULT              # The entry: 0|DEFAULT is reserved and always required.
> 
> +
> 
> +################################################################
> ################
> 
> +#
> 
> +# Library Class section - list of all Library Classes needed by this Platform.
> 
> +#
> 
> +################################################################
> ################
> 
> +
> 
> +[LibraryClasses]
> 
> +  PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf
> 
> +  PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
> 
> +
> DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDe
> bugPrintErrorLevelLib.inf
> 
> +  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
> 
> +  IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
> 
> +  PciLib|MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf
> 
> +  PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
> 
> +  PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf
> 
> +
> BaseMemoryLib|MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr
> .inf
> 
> +  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
> 
> +  PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
> 
> +  HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
> 
> +
> PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiSe
> rvicesTablePointerLibIdt.inf
> 
> +  PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
> 
> +
> MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllo
> cationLib.inf
> 
> +
> PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeC
> offGetEntryPointLib.inf
> 
> +
> ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiRepo
> rtStatusCodeLib.inf
> 
> +
> CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCache
> MaintenanceLib.inf
> 
> +  PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
> 
> +
> PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCo
> ffExtraActionLibNull.inf
> 
> +
> UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecomp
> ressLib.inf
> 
> +
> SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizati
> onLib.inf
> 
> +  CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
> 
> +
> ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtrac
> tGuidedSectionLib.inf
> 
> +  CacheLib|IntelFsp2Pkg/Library/BaseCacheLib/BaseCacheLib.inf
> 
> +
> CacheAsRamLib|IntelFsp2Pkg/Library/BaseCacheAsRamLibNull/BaseCacheAsRa
> mLibNull.inf
> 
> +
> FspSwitchStackLib|IntelFsp2Pkg/Library/BaseFspSwitchStackLib/BaseFspSwitchS
> tackLib.inf
> 
> +
> FspCommonLib|IntelFsp2Pkg/Library/BaseFspCommonLib/BaseFspCommonLib.i
> nf
> 
> +
> FspPlatformLib|IntelFsp2Pkg/Library/BaseFspPlatformLib/BaseFspPlatformLib.in
> f
> 
> +
> PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatfo
> rmHookLibNull.inf
> 
> +
> PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLib
> Null.inf
> 
> +
> OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/
> OemHookStatusCodeLibNull.inf
> 
> +  UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
> 
> +!if $(TARGET) == DEBUG
> 
> +
> DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
> 
> +
> SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib
> 16550.inf
> 
> +!else
> 
> +  DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
> 
> +  SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf
> 
> +!endif
> 
> +
> 
> +
> 
> +################################################################
> ################
> 
> +#
> 
> +# Pcd Section - list of all EDK II PCD Entries defined by this Platform
> 
> +#
> 
> +################################################################
> ################
> 
> +[PcdsFixedAtBuild]
> 
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnS3Boot    | TRUE
> 
> +  gQemuFspPkgTokenSpaceGuid.PcdFspHeaderRevision          | 0x03
> 
> +  gQemuFspPkgTokenSpaceGuid.PcdFspImageIdString           | $(FSP_IMAGE_ID)
> 
> +  gQemuFspPkgTokenSpaceGuid.PcdFspImageRevision           |
> $(FSP_IMAGE_REV)
> 
> +  #
> 
> +  # FSP CAR Usages  (BL RAM | FSP RAM | FSP CODE)
> 
> +  #
> 
> +  gIntelFsp2PkgTokenSpaceGuid.PcdTemporaryRamBase         |
> $(CAR_BASE_ADDRESS)
> 
> +  gIntelFsp2PkgTokenSpaceGuid.PcdTemporaryRamSize         |
> $(CAR_REGION_SIZE)
> 
> +  gIntelFsp2PkgTokenSpaceGuid.PcdFspTemporaryRamSize      |
> $(CAR_FSP_REGION_SIZE)
> 
> +  gIntelFsp2PkgTokenSpaceGuid.PcdFspReservedBufferSize    | 0x0100
> 
> +
> 
> +  # This defines how much space will be used for heap in FSP temporary
> memory
> 
> +  # x % of FSP temporary memory will be used for heap
> 
> +  # (100 - x) % of FSP temporary memory will be used for stack
> 
> +  gIntelFsp2PkgTokenSpaceGuid.PcdFspHeapSizePercentage    | 65
> 
> +
> 
> +  # This is a platform specific global pointer used by FSP
> 
> +  gIntelFsp2PkgTokenSpaceGuid.PcdGlobalDataPointerAddress | 0xFED00148
> 
> +  gIntelFsp2PkgTokenSpaceGuid.PcdFspReservedMemoryLength  | 0x00100000
> 
> +
> 
> +!if $(TARGET) == RELEASE
> 
> +  gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel   | 0x00000000
> 
> +  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask           | 0
> 
> +!else
> 
> +  gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel   | 0x80000047
> 
> +  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask           | 0x27
> 
> +!endif
> 
> +
> 
> +[PcdsPatchableInModule]
> 
> +  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress       | 0xE0000000
> 
> +  #
> 
> +  # This entry will be patched during the build process
> 
> +  #
> 
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress        | 0x12345678
> 
> +
> 
> +!if $(TARGET) == RELEASE
> 
> +  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel        | 0
> 
> +!else
> 
> +  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel        | 0x80000047
> 
> +!endif
> 
> +
> 
> +[PcdsDynamicVpd.Upd]
> 
> +  #
> 
> +  # This section is not used by the normal build process
> 
> +  # However, FSP will use dedicated tool to handle it and generate a
> 
> +  # VPD similar binary block (User Configuration Data). This block will
> 
> +  # be accessed through a generated data structure directly rather than
> 
> +  # PCD services. This is for size consideration.
> 
> +  # Format:
> 
> +  #   gQemuFspPkgTokenSpaceGuid.Updxxxxxxxxxxxxn      | OFFSET | LENGTH |
> VALUE
> 
> +  # Only simple data type is supported
> 
> +  #
> 
> +
> 
> +  #
> 
> +  # Comments with !BSF will be used to generate BSF file
> 
> +  # Comments with !HDR will be used to generate H header file
> 
> +  #
> 
> +
> 
> +  # Global definitions in BSF
> 
> +  # !BSF PAGES:{TMP:"FSP T", MEM:"FSP MemoryInit Settings", SIL:"FSP
> SiliconInit Settings"}
> 
> +  # !BSF BLOCK:{NAME:"QEMU Platform", VER:"0.1"}
> 
> +
> 
> +  # !BSF FIND:{QEMUPD_T}
> 
> +  # !HDR COMMENT:{FSP_UPD_HEADER:FSP UPD Header}
> 
> +  # !HDR EMBED:{FSP_UPD_HEADER:FspUpdHeader:START}
> 
> +  # FsptUpdSignature: {QEMUPD_T}
> 
> +  gQemuFspPkgTokenSpaceGuid.Signature                   | * | 0x08 |
> 0x545F4450554D4551
> 
> +  # !BSF NAME:{FsptUpdRevision}
> 
> +  gQemuFspPkgTokenSpaceGuid.Revision                    | * | 0x01 | 0x01
> 
> +  # !HDR EMBED:{FSP_UPD_HEADER:FspUpdHeader:END}
> 
> +  gQemuFspPkgTokenSpaceGuid.Reserved                    | * | 0x17 | {0x00}
> 
> +
> 
> +  # !HDR COMMENT:{FSPT_ARCH_UPD:FSPT_ARCH_UPD}
> 
> +  # !HDR EMBED:{FSPT_ARCH_UPD:FsptArchUpd:START}
> 
> +  gQemuFspPkgTokenSpaceGuid.Revision                    | * | 0x01 | 0x01
> 
> +  gQemuFspPkgTokenSpaceGuid.Reserved                    | * | 0x03 | {0x00}
> 
> +  gQemuFspPkgTokenSpaceGuid.Length                      | * | 0x04 | 0x00000020
> 
> +  gQemuFspPkgTokenSpaceGuid.FspDebugHandler             | * | 0x04 |
> 0x00000000
> 
> +  # !HDR EMBED:{FSPT_ARCH_UPD:FsptArchUpd:END}
> 
> +  gQemuFspPkgTokenSpaceGuid.Reserved1                   | * | 0x14 | {0x00}
> 
> +
> 
> +  # !HDR COMMENT:{FSPT_COMMON_UPD:Fsp T Common UPD}
> 
> +  # !HDR EMBED:{FSPT_COMMON_UPD:FsptCommonUpd:START}
> 
> +  gQemuFspPkgTokenSpaceGuid.Revision                    | * | 0x01 | 0x01
> 
> +  gQemuFspPkgTokenSpaceGuid.Reserved                    | * | 0x03 | {0x00}
> 
> +
> 
> +  # Base address of the microcode region.
> 
> +  gQemuFspPkgTokenSpaceGuid.MicrocodeRegionBase         | * | 0x04 |
> 0x00000000
> 
> +
> 
> +  # Length of the microcode region.
> 
> +  gQemuFspPkgTokenSpaceGuid.MicrocodeRegionLength       | * | 0x04 |
> 0x00000000
> 
> +
> 
> +  # Base address of the cacheable flash region.
> 
> +  gQemuFspPkgTokenSpaceGuid.CodeRegionBase              | * | 0x04 |
> 0x00000000
> 
> +
> 
> +  # Length of the cacheable flash region.
> 
> +  gQemuFspPkgTokenSpaceGuid.CodeRegionLength            | * | 0x04 |
> 0x00000000
> 
> +
> 
> +  # !HDR EMBED:{FSPT_COMMON_UPD:FsptCommonUpd:END}
> 
> +  gQemuFspPkgTokenSpaceGuid.Reserved1                   | * | 0x0C | {0x00}
> 
> +
> 
> +  # !HDR COMMENT:{FSP_T_CONFIG:Fsp T Configuration}
> 
> +  # !HDR EMBED:{FSP_T_CONFIG:FsptConfig:START}
> 
> +  # !BSF PAGE:{TMP}
> 
> +  # !BSF NAME:{Chicken bytes to test Hex config}
> 
> +  # !BSF TYPE:{EditNum, HEX, (0x00000000,0xFFFFFFFF)}
> 
> +  # !BSF HELP:{This option shows how to present option for 4 bytes data}
> 
> +  gQemuFspPkgTokenSpaceGuid.ChickenBytes                | * | 0x04 | 0x00000000
> 
> +
> 
> +  # !HDR EMBED:{FSP_T_CONFIG:FsptConfig:END}
> 
> +  gQemuFspPkgTokenSpaceGuid.ReservedFsptUpd1            | * | 0x1C | {0x00}
> 
> +
> 
> +  # Note please keep "UpdTerminator" at the end of each UPD region.
> 
> +  # The tool will use this field to determine the actual end of the UPD data
> 
> +  # structure.
> 
> +  gQemuFspPkgTokenSpaceGuid.UpdTerminator               | * | 0x02 | 0x55AA
> 
> +
> 
> +
> #################################################################
> ###############
> 
> +  #
> 
> +  # UPDs consumed in FspMemoryInit Api
> 
> +  #
> 
> +
> #################################################################
> ###############
> 
> +  # !BSF FIND:{QEMUPD_M}
> 
> +  # !HDR COMMENT:{FSP_UPD_HEADER:FSP UPD Header}
> 
> +  # !HDR EMBED:{FSP_UPD_HEADER:FspUpdHeader:START}
> 
> +  # FspmUpdSignature: {QEMUPD_M}
> 
> +  gQemuFspPkgTokenSpaceGuid.Signature                   | * | 0x08 |
> 0x4D5F4450554D4551
> 
> +  # !BSF NAME:{FspmUpdRevision}
> 
> +  gQemuFspPkgTokenSpaceGuid.Revision                    | * | 0x01 | 0x01
> 
> +  # !HDR EMBED:{FSP_UPD_HEADER:FspUpdHeader:END}
> 
> +  gQemuFspPkgTokenSpaceGuid.Reserved                    | * | 0x17 | {0x00}
> 
> +
> 
> +  # !HDR COMMENT:{FSPM_ARCH_UPD:Fsp M Architectural UPD}
> 
> +  # !HDR EMBED:{FSPM_ARCH_UPD:FspmArchUpd:START}
> 
> +
> 
> +  gQemuFspPkgTokenSpaceGuid.Revision                    | * | 0x01 | 0x01
> 
> +
> 
> +  gQemuFspPkgTokenSpaceGuid.Reserved                    | * | 0x03 | {0x00}
> 
> +
> 
> +  # !HDR STRUCT:{VOID*}
> 
> +  gQemuFspPkgTokenSpaceGuid.NvsBufferPtr                | * | 0x04 | 0x00000000
> 
> +
> 
> +  # !HDR STRUCT:{VOID*}
> 
> +  # !BSF NAME:{StackBase}
> 
> +  # !BSF HELP:{Stack base for FSP use. Default: 0xFEF16000}
> 
> +  gQemuFspPkgTokenSpaceGuid.StackBase                   | * | 0x04 |
> $(CAR_BLD_REGION_SIZE)
> 
> +
> 
> +  # !BSF NAME:{StackSize}
> 
> +  # !BSF HELP:{To pass the stack size for FSP use. Bootloader can
> programmatically get the FSP requested StackSize by using the defaults in the
> FSP-M component. This is the minimum stack size expected by this revision of
> FSP. Default: 0x2A000}
> 
> +  gQemuFspPkgTokenSpaceGuid.StackSize                   | * | 0x04 |
> $(CAR_FSP_REGION_SIZE)
> 
> +
> 
> +  # !BSF NAME:{BootLoaderTolumSize}
> 
> +  # !BSF HELP:{To pass Bootloader Tolum size.}
> 
> +  gQemuFspPkgTokenSpaceGuid.BootLoaderTolumSize         | * | 0x04 |
> 0x00000000
> 
> +
> 
> +  # !BSF NAME:{Bootmode}
> 
> +  # !BSF HELP:{To maintain Bootmode details.}
> 
> +  gPlatformFspPkgTokenSpaceGuid.Bootmode                   | * | 0x04 |
> 0x00000000
> 
> +
> 
> +  # !HDR EMBED:{FSPM_ARCH_UPD:FspmArchUpd:END}
> 
> +  gQemuFspPkgTokenSpaceGuid.Reserved1                   | * | 0x08 | {0x00}
> 
> +
> 
> +  # !HDR COMMENT:{FSP_M_CONFIG:Fsp M Configuration}
> 
> +  # !HDR EMBED:{FSP_M_CONFIG:FspmConfig:START}
> 
> +  # !BSF PAGE:{MEM}
> 
> +  # !BSF NAME:{Debug Serial Port Base address}
> 
> +  # !BSF TYPE:{EditNum, HEX, (0x00000000,0xFFFFFFFF)}
> 
> +  # !BSF HELP:{Debug serial port base address. This option will be used only
> when the 'Serial Port Debug Device'}
> 
> +  # !BSF HELP:{+ option is set to 'External Device'. 0x00000000(Default).}
> 
> +  gQemuFspPkgTokenSpaceGuid.SerialDebugPortAddress      | * | 0x04 |
> 0x00000000
> 
> +
> 
> +  # !BSF NAME:{Debug Serial Port Type} TYPE:{Combo}
> 
> +  # !BSF OPTION:{0:NONE, 1:I/O, 2:MMIO}
> 
> +  # !BSF HELP:{16550 compatible debug serial port resource type. NONE means
> no serial port support. 0x02:MMIO(Default).}
> 
> +  gQemuFspPkgTokenSpaceGuid.SerialDebugPortType         | * | 0x01 | 0x02
> 
> +
> 
> +  # !BSF NAME:{Serial Port Debug Device} TYPE:{Combo}
> 
> +  # !BSF OPTION:{0:SOC UART0, 1:SOC UART1, 2:SOC UART2, 3:External Device}
> 
> +  # !BSF HELP:{Select active serial port device for debug. }
> 
> +  # !BSF HELP:{+For SOC UART devices,'Debug Serial Port Base' options will be
> ignored. 0x02:SOC UART2(Default).}
> 
> +  gQemuFspPkgTokenSpaceGuid.SerialDebugPortDevice       | * | 0x01 | 0x02
> 
> +
> 
> +  # !BSF NAME:{Debug Serial Port Stride Size} TYPE:{Combo}
> 
> +  # !BSF OPTION:{0:1, 2:4}
> 
> +  # !BSF HELP:{Debug serial port register map stride size in bytes. 0x00:1,
> 0x02:4(Default).}
> 
> +  gQemuFspPkgTokenSpaceGuid.SerialDebugPortStrideSize   | * | 0x01 | 0x02
> 
> +
> 
> +
> 
> +  # !HDR EMBED:{FSP_M_CONFIG:FspmConfig:END}
> 
> +  gQemuFspPkgTokenSpaceGuid.ReservedFspmUpd             | * | 0x04 | {0x00}
> 
> +
> 
> +
> 
> +  # Note please keep "UpdTerminator" at the end of each UPD region.
> 
> +  # The tool will use this field to determine the actual end of the UPD data
> 
> +  # structure.
> 
> +  gQemuFspPkgTokenSpaceGuid.UpdTerminator               | * | 0x02 | 0x55AA
> 
> +
> 
> +
> #################################################################
> ###############
> 
> +  #
> 
> +  # UPDs consumed in FspSiliconInit Api
> 
> +  #
> 
> +
> #################################################################
> ###############
> 
> +  # !BSF FIND:{QEMUPD_S}
> 
> +  # !HDR COMMENT:{FSP_UPD_HEADER:FSP UPD Header}
> 
> +  # !HDR EMBED:{FSP_UPD_HEADER:FspUpdHeader:START}
> 
> +  # FspsUpdSignature: {QEMUPD_S}
> 
> +  gQemuFspPkgTokenSpaceGuid.Signature                   | * | 0x08 |
> 0x535F4450554D4551
> 
> +  # !BSF NAME:{FspsUpdRevision}
> 
> +  gQemuFspPkgTokenSpaceGuid.Revision                    | * | 0x01 | 0x01
> 
> +  # !HDR EMBED:{FSP_UPD_HEADER:FspUpdHeader:END}
> 
> +  gQemuFspPkgTokenSpaceGuid.Reserved                    | * | 0x17 | {0x00}
> 
> +
> 
> +  # !HDR COMMENT:{FSPS_ARCH_UPD:FSPS_ARCH_UPD}
> 
> +  # !HDR EMBED:{FSPS_ARCH_UPD:FspsArchUpd:START}
> 
> +  gQemuFspPkgTokenSpaceGuid.Revision                    | * | 0x01 | 0x01
> 
> +  gQemuFspPkgTokenSpaceGuid.Reserved                    | * | 0x03 | {0x00}
> 
> +  gQemuFspPkgTokenSpaceGuid.Length                      | * | 0x04 | 0x00000020
> 
> +  gQemuFspPkgTokenSpaceGuid.FspEventHandler             | * | 0x04 |
> 0x00000000
> 
> +  gQemuFspPkgTokenSpaceGuid.EnableMultiPhaseSiliconInit | * | 0x01 | 0x00
> 
> +  # !HDR EMBED:{FSPS_ARCH_UPD:FspsArchUpd:END}
> 
> +  gQemuFspPkgTokenSpaceGuid.Reserved1                   | * | 0x13 | {0x00}
> 
> +
> 
> +  # !HDR COMMENT:{FSP_S_CONFIG:Fsp S Configuration}
> 
> +  # !HDR EMBED:{FSP_S_CONFIG:FspsConfig:START}
> 
> +  # !BSF PAGE:{SIL}
> 
> +
> 
> +  # !BSF NAME:{BMP Logo Data Size}
> 
> +  # !BSF TYPE:{Reserved}
> 
> +  # !BSF HELP:{BMP logo data buffer size. 0x00000000(Default).}
> 
> +  gQemuFspPkgTokenSpaceGuid.LogoSize                    | * | 0x04 | 0x00000000
> 
> +
> 
> +  # !BSF NAME:{BMP Logo Data Pointer}
> 
> +  # !BSF TYPE:{Reserved}
> 
> +  # !BSF HELP:{BMP logo data pointer to a BMP format buffer.
> 0x00000000(Default).}
> 
> +  gQemuFspPkgTokenSpaceGuid.LogoPtr                     | * | 0x04 | 0x00000000
> 
> +
> 
> +  # !BSF NAME:{Graphics Configuration Data Pointer}
> 
> +  # !BSF TYPE:{Reserved}
> 
> +  # !BSF HELP:{Graphics configuration data used for initialization.
> 0x00000000(Default).}
> 
> +  gQemuFspPkgTokenSpaceGuid.GraphicsConfigPtr           | * | 0x04 |
> 0x00000000
> 
> +
> 
> +  # !BSF NAME:{PCI GFX Temporary MMIO Base}
> 
> +  # !BSF TYPE:{EditNum, HEX, (0x80000000,0xDFFFFFFF)}
> 
> +  # !BSF HELP:{PCI Temporary PCI GFX Base used before full PCI enumeration.
> 0x80000000(Default).}
> 
> +  gQemuFspPkgTokenSpaceGuid.PciTempResourceBase         | * | 0x04 |
> 0x80000000
> 
> +
> 
> +  # !HDR EMBED:{FSP_S_CONFIG:FspsConfig:END}
> 
> +  gQemuFspPkgTokenSpaceGuid.ReservedFspsUpd             | * | 0x01 | 0x00
> 
> +
> 
> +  # Note please keep "UpdTerminator" at the end of each UPD region.
> 
> +  # The tool will use this field to determine the actual end of the UPD data
> 
> +  # structure.
> 
> +  gQemuFspPkgTokenSpaceGuid.UpdTerminator               | * | 0x02 | 0x55AA
> 
> +
> 
> +################################################################
> ###################################
> 
> +#
> 
> +# Components Section - list of the modules and components that will be
> processed by compilation
> 
> +#                      tools and the EDK II tools to generate PE32/PE32+/Coff image
> files.
> 
> +#
> 
> +# Note: The EDK II DSC file is not used to specify how compiled binary images
> get placed
> 
> +#       into firmware volume images. This section is just a list of modules to
> compile from
> 
> +#       source into UEFI-compliant binaries.
> 
> +#       It is the FDF file that contains information on combining binary files into
> firmware
> 
> +#       volume images, whose concept is beyond UEFI and is described in PI
> specification.
> 
> +#       Binary modules do not need to be listed in this section, as they should be
> 
> +#       specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT
> binary (Fat.efi),
> 
> +#       Logo (Logo.bmp), and etc.
> 
> +#       There may also be modules listed in this section that are not required in
> the FDF file,
> 
> +#       When a module listed here is excluded from FDF file, then UEFI-compliant
> binary will be
> 
> +#       generated for it, but the binary will not be put into any firmware volume.
> 
> +#
> 
> +################################################################
> ###################################
> 
> +[Components.IA32]
> 
> +  #
> 
> +  # FSP Binary Components
> 
> +  #
> 
> +  $(FSP_PACKAGE)/FspHeader/FspHeader.inf
> 
> +
> 
> +  #
> 
> +  # SEC
> 
> +  #
> 
> +  IntelFsp2Pkg/FspSecCore/FspSecCoreT.inf {
> 
> +    <LibraryClasses>
> 
> +
> FspSecPlatformLib|$(FSP_PACKAGE)/Library/PlatformSecLib/Vtf0PlatformSecTLi
> b.inf
> 
> +  }
> 
> +
> 
> +[Components.$(FSP_ARCH)]
> 
> +  IntelFsp2Pkg/FspSecCore/FspSecCoreV.inf {
> 
> +    <LibraryClasses>
> 
> +
> FspSecPlatformLib|$(FSP_PACKAGE)/Library/PlatformSecLib/Vtf0PlatformSecVLi
> b.inf
> 
> +  }
> 
> +
> 
> +  IntelFsp2Pkg/FspSecCore/FspSecCoreM.inf {
> 
> +    <LibraryClasses>
> 
> +
> FspSecPlatformLib|$(FSP_PACKAGE)/Library/PlatformSecLib/Vtf0PlatformSecML
> ib.inf
> 
> +  }
> 
> +
> 
> +  IntelFsp2Pkg/FspSecCore/FspSecCoreS.inf {
> 
> +    <LibraryClasses>
> 
> +
> FspSecPlatformLib|$(FSP_PACKAGE)/Library/PlatformSecLib/Vtf0PlatformSecSLi
> b.inf
> 
> +  }
> 
> +
> 
> +  #
> 
> +  # PEI Core
> 
> +  #
> 
> +  MdeModulePkg/Core/Pei/PeiMain.inf
> 
> +
> 
> +  #
> 
> +  # PCD
> 
> +  #
> 
> +  MdeModulePkg/Universal/PCD/Pei/Pcd.inf {
> 
> +    <LibraryClasses>
> 
> +      DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
> 
> +      PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> 
> +  }
> 
> +
> 
> +  $(FSP_PACKAGE)/FspvInit/FspvInit.inf
> 
> +  $(FSP_PACKAGE)/FspmInit/FspmInit.inf
> 
> +  $(FSP_PACKAGE)/FspsInit/FspsInit.inf
> 
> +  $(FSP_PACKAGE)/QemuVideo/QemuVideo.inf
> 
> +  MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf {
> 
> +    <LibraryClasses>
> 
> +
> DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull
> .inf
> 
> +
> ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSys
> temLibNull.inf
> 
> +  }
> 
> +  IntelFsp2Pkg/FspNotifyPhase/FspNotifyPhasePeim.inf
> 
> +
> 
> +################################################################
> ###################################
> 
> +#
> 
> +# BuildOptions Section - Define the module specific tool chain flags that should
> be used as
> 
> +#                        the default flags for a module. These flags are appended to any
> 
> +#                        standard flags that are defined by the build process. They can be
> 
> +#                        applied for any modules or only those modules with the specific
> 
> +#                        module style (EDK or EDKII) specified in [Components] section.
> 
> +#
> 
> +################################################################
> ###################################
> 
> +[BuildOptions]
> 
> +# Append build options for EDK and EDKII drivers (= is Append, == is Replace)
> 
> +  # Enable link-time optimization when building with GCC49
> 
> +  *_GCC49_IA32_CC_FLAGS = -flto
> 
> +  *_GCC49_IA32_DLINK_FLAGS = -flto
> 
> +  *_GCC5_IA32_CC_FLAGS = -fno-pic
> 
> +  *_GCC5_IA32_DLINK_FLAGS = -no-pie
> 
> +  *_GCC5_IA32_ASLCC_FLAGS = -fno-pic
> 
> +  *_GCC5_IA32_ASLDLINK_FLAGS = -no-pie
> 
> diff --git a/IntelFsp2Pkg/Tools/Tests/test_yaml.py
> b/IntelFsp2Pkg/Tools/Tests/test_yaml.py
> new file mode 100644
> index 0000000000..d81d7f7c4e
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/Tests/test_yaml.py
> @@ -0,0 +1,96 @@
> +# @file
> 
> +#  Split a file into two pieces at the request offset.
> 
> +#
> 
> +#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +#
> 
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +# Import Modules
> 
> +import unittest
> 
> +import tempfile
> 
> +import os
> 
> +import shutil
> 
> +import struct as st
> 
> +import filecmp
> 
> +
> 
> +import os, sys
> 
> +currentdir = os.path.dirname(os.path.realpath(__file__))
> 
> +parentdir = os.path.dirname(currentdir)
> 
> +sys.path.append(parentdir)
> 
> +import FspDscBsf2Yaml
> 
> +
> 
> +YamlHeaderLineLength = 10
> 
> +HdrFileHeaderLineLength = 32
> 
> +BsfFileHeaderLineLength = 19
> 
> +
> 
> +def GenFileWithoutHdr(inputfile, numLineToStrip):
> 
> +    yaml_file = open(inputfile, "r")
> 
> +    lines = yaml_file.readlines()
> 
> +    yaml_file.close()
> 
> +    del lines[:numLineToStrip]
> 
> +
> 
> +    noHdrOutputFileName = "no-header-" + inputfile
> 
> +    stripped_file = open(noHdrOutputFileName, "w")
> 
> +    for line in lines:
> 
> +        stripped_file.write(line)
> 
> +    stripped_file.close()
> 
> +    return noHdrOutputFileName
> 
> +
> 
> +class TestFspScripts(unittest.TestCase):
> 
> +    def test_generateFspHeader_fromDsc(self):
> 
> +        # Generate HEADER
> 
> +        cmd = '{} {} HEADER {} {} {}'.format(
> 
> +            'python',
> 
> +            '..\GenCfgOpt.py',
> 
> +            'QemuFspPkg.dsc',
> 
> +            '.',
> 
> +            "")
> 
> +        os.system(cmd)
> 
> +        noHdrOutputFileName = GenFileWithoutHdr("FspUpd.h",
> HdrFileHeaderLineLength)
> 
> +        self.assertTrue(filecmp.cmp(noHdrOutputFileName,
> 
> +                  'ExpectedFspUpd.h'))
> 
> +
> 
> +    def test_generateFspsHeader_fromDsc(self):
> 
> +        noHdrOutputFileName = GenFileWithoutHdr("FspsUpd.h",
> HdrFileHeaderLineLength)
> 
> +        self.assertTrue(filecmp.cmp(noHdrOutputFileName,
> 
> +                  'ExpectedFspsUpd.h'))
> 
> +
> 
> +    def test_generateFsptHeader_fromDsc(self):
> 
> +        noHdrOutputFileName = GenFileWithoutHdr("FsptUpd.h",
> HdrFileHeaderLineLength)
> 
> +        self.assertTrue(filecmp.cmp(noHdrOutputFileName,
> 
> +                  'ExpectedFsptUpd.h'))
> 
> +
> 
> +    def test_generateFspmHeader_fromDsc(self):
> 
> +        noHdrOutputFileName = GenFileWithoutHdr("FspmUpd.h",
> HdrFileHeaderLineLength)
> 
> +        self.assertTrue(filecmp.cmp(noHdrOutputFileName,
> 
> +                  'ExpectedFspmUpd.h'))
> 
> +
> 
> +    def test_generateBsf_fromDsc(self):
> 
> +        # Generate BSF
> 
> +        cmd = '{} {} GENBSF {} {} {}'.format(
> 
> +            'python',
> 
> +            '..\GenCfgOpt.py',
> 
> +            'QemuFspPkg.dsc',
> 
> +            '.',
> 
> +            "Output.bsf")
> 
> +        os.system(cmd)
> 
> +        noHdrOutputFileName = GenFileWithoutHdr("Output.bsf",
> BsfFileHeaderLineLength)
> 
> +        self.assertTrue(filecmp.cmp(noHdrOutputFileName,
> 
> +                  'ExpectedOutput.bsf'))
> 
> +
> 
> +    def test_generateYaml_fromDsc(self):
> 
> +        # Generate YAML
> 
> +        cmd = '{} {} {} {}'.format(
> 
> +            'python',
> 
> +            '..\FspDscBsf2Yaml.py',
> 
> +            'QemuFspPkg.dsc',
> 
> +            "Output.yaml")
> 
> +        os.system(cmd)
> 
> +        noHdrOutputFileName = GenFileWithoutHdr("Output.yaml",
> YamlHeaderLineLength)
> 
> +        self.assertTrue(filecmp.cmp(noHdrOutputFileName,
> 
> +                  'ExpectedOutput.yaml'))
> 
> +
> 
> +if __name__ == '__main__':
> 
> +    unittest.main()
> 
> diff --git a/IntelFsp2Pkg/Tools/UserManuals/FspDscBsf2YamlUserManual.md
> b/IntelFsp2Pkg/Tools/UserManuals/FspDscBsf2YamlUserManual.md
> new file mode 100644
> index 0000000000..ba2311445c
> --- /dev/null
> +++ b/IntelFsp2Pkg/Tools/UserManuals/FspDscBsf2YamlUserManual.md
> @@ -0,0 +1,39 @@
> +#Name
> 
> +**FspDscBsf2Yaml.py** The python script that generates YAML file for
> 
> +the Boot Settings from an EDK II Platform Description (**DSC**) file
> 
> +or from a Boot Settings File (**BSF**). It is created to help
> 
> +transitioning FSP Updateable Product Data (**UPD**) file format to
> 
> +new standardized YAML format so that it can be configured through
> 
> +open source tools.
> 
> +
> 
> +#Synopsis
> 
> +```
> 
> +FspDscBsf2Yaml DscFile|BsfFile  YamlFile
> 
> +```
> 
> +
> 
> +#Description
> 
> +**FspDscBsf2Yaml.py** is a script that generates configuration options from
> an
> 
> +**EDK II Platform Description (DSC)** file or **a Boot Settings File (BSF)** file.
> 
> +
> 
> +It generates a **YAML file** that can be used by the **Config Editor** to
> provide
> 
> +a graphical user interface for manipulating settings in the UPD regions.
> 
> +
> 
> +The following sections explain the usage of this script.
> 
> +
> 
> +## 1. FspDscBsf2Yaml.py DscFile YamlFile
> 
> +
> 
> +The **DscFile** option is an input DSC file.
> 
> +
> 
> +The **YamlFile** option is an output YAML file.
> 
> +
> 
> +The script takes the FSP DSC file consisting BSF syntax and generates a YAML
> 
> +output file describing the boot settings.
> 
> +
> 
> +## 2. FspDscBsf2Yaml.py BsfFile YamlFile
> 
> +
> 
> +The **BsfFile** option is an input BSF file.
> 
> +
> 
> +The **YamlFile** option is an output YAML file.
> 
> +
> 
> +The script generates a YAML output file from a BSF file. The BSF file
> 
> +can be generated using GenCfgOpt tool.
> 
> --
> 2.28.0.windows.1


      reply	other threads:[~2021-02-05  2:09 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-04  3:59 [PATCH v2] IntelFsp2Pkg: Add YAML file generation support Tung Lun
2021-02-05  2:09 ` Chiu, Chasel [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=SN6PR11MB2814F9C03DFE3716DE9598C4E6B29@SN6PR11MB2814.namprd11.prod.outlook.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox