Update FSP to follow:
https://firmware.intel.com/sites/default/files/FSP_EAS_v2.0_Draft%20External.pdf
Update BSF handler to follow:
https://firmware.intel.com/sites/default/files/BSF_1_0.pdf

Update PatchFv tool to align with FSP2.0 to handle FSP-T, FSP-M, FSP-S.
Update GenCfgOpt to follow BSF1.0.
Add FspTool to split a FSP 2.0 compatibale image into individual FSP-T/M/S
and generate the mapping header file

Cc: Giri P Mudusuru <giri.p.mudus...@intel.com>
Cc: Maurice Ma <maurice...@intel.com>
Cc: Ravi P Rangarajan <ravi.p.rangara...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen....@intel.com>
Reviewed-by: Giri P Mudusuru <giri.p.mudus...@intel.com>
Reviewed-by: Maurice Ma <maurice...@intel.com>
Reviewed-by: Ravi P Rangarajan <ravi.p.rangara...@intel.com>
---
 IntelFspPkg/Tools/FspTool.py                           | 363 ++++++++++
 IntelFspPkg/Tools/GenCfgOpt.py                         | 739 
++++++++++++--------
 IntelFspPkg/Tools/PatchFv.py                           | 106 ++-
 IntelFspPkg/Tools/UserManuals/GenCfgOptUserManual.docx | Bin 24424 -> 28336 
bytes
 4 files changed, 882 insertions(+), 326 deletions(-)

diff --git a/IntelFspPkg/Tools/FspTool.py b/IntelFspPkg/Tools/FspTool.py
new file mode 100644
index 0000000..512304b
--- /dev/null
+++ b/IntelFspPkg/Tools/FspTool.py
@@ -0,0 +1,363 @@
+## @ FspTool.py
+#
+# Copyright (c) 2015 - 2016, 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 that 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.
+#
+##
+
+import os
+import sys
+import uuid
+import copy
+import struct
+import argparse
+from   ctypes import *
+
+"""
+This utility supports some operations for Intel FSP image.
+It supports:
+    - Split a FSP 2.0 compatibale image into individual FSP-T/M/S/C
+        and generate the mapping header file.
+"""
+
+class c_uint24(Structure):
+    """Little-Endian 24-bit Unsigned Integer"""
+    _pack_   = 1
+    _fields_ = [
+        ('Data', (c_uint8 * 3))
+        ]
+
+    def __init__(self, val=0):
+        self.set_value(val)
+
+    def __str__(self, indent=0):
+        return '0x%.6x' % self.value
+
+    def get_value(self):
+        return (
+            (self.Data[0]      ) +
+            (self.Data[1] <<  8) +
+            (self.Data[2] << 16)
+            )
+
+    def set_value(self, val):
+        self.Data[0] = (val      ) & 0xff
+        self.Data[1] = (val >>  8) & 0xff
+        self.Data[2] = (val >> 16) & 0xff
+
+    value = property(get_value, set_value)
+
+class EFI_FIRMWARE_VOLUME_HEADER(Structure):
+    _fields_ = [
+        ('ZeroVector',                 ARRAY(c_uint8, 16)),
+        ('FileSystemGuid',             ARRAY(c_char, 16)),
+        ('FvLength',                   c_uint64),
+        ('Signature',                  c_uint32),
+        ('Attributes',                 c_uint32),
+        ('HeaderLength',               c_uint16),
+        ('Checksum',                   c_uint16),
+        ('ExtHeaderOffset',            c_uint16),
+        ('Reserved',                   c_uint8),
+        ('Revision',                   c_uint8)
+        ]
+
+class EFI_FIRMWARE_VOLUME_EXT_HEADER(Structure):
+    _fields_ = [
+        ('FvName',                     ARRAY(c_char, 16)),
+        ('ExtHeaderSize',              c_uint32)
+        ]
+
+class EFI_FFS_INTEGRITY_CHECK(Structure):
+    _fields_ = [
+        ('Header',                     c_uint8),
+        ('File',                       c_uint8)
+        ]
+
+class EFI_FFS_FILE_HEADER(Structure):
+    _fields_ = [
+        ('Name',                       ARRAY(c_char, 16)),
+        ('IntegrityCheck',             EFI_FFS_INTEGRITY_CHECK),
+        ('Type',                       c_uint8),
+        ('Attributes',                 c_uint8),
+        ('Size',                       c_uint24),
+        ('State',                      c_uint8)
+        ]
+
+class EFI_COMMON_SECTION_HEADER(Structure):
+    _fields_ = [
+        ('Size',                       c_uint24),
+        ('Type',                       c_uint8)
+        ]
+
+class FSP_INFORMATION_HEADER(Structure):
+     _fields_ = [
+        ('Signature',                   c_uint32),
+        ('HeaderLength',                c_uint32),
+        ('Reserved1',                   ARRAY(c_uint8, 3)),
+        ('HeaderRevision',              c_uint8),
+        ('ImageRevision',               c_uint32),
+        ('ImageId',                     c_uint64),
+        ('ImageSize',                   c_uint32),
+        ('ImageBase',                   c_uint32),
+        ('ImageAttribute',              c_uint32),
+        ('CfgRegionOffset',             c_uint32),
+        ('CfgRegionSize',               c_uint32),
+        ('ApiEntryNum',                 c_uint32),
+        ('NemInitEntry',                c_uint32),
+        ('FspInitEntry',                c_uint32),
+        ('NotifyPhaseEntry',            c_uint32),
+        ('FspMemoryInitEntry',          c_uint32),
+        ('TempRamExitEntry',            c_uint32),
+        ('FspSiliconInitEntry',         c_uint32)
+    ]
+
+class FspFv:
+    HeaderFile = """/*
+ *
+ * Automatically generated file; DO NOT EDIT.
+ * FSP mapping file
+ *
+ */
+"""
+    FspNameDict = {
+        "0" : "-C.Fv",
+        "1" : "-T.Fv",
+        "2" : "-M.Fv",
+        "3" : "-S.Fv",
+    }
+
+    def __init__(self, FvBin):
+        self.FspFv  = {}
+        self.FvList = []
+        self.FspBin = FvBin
+        hfsp = open (self.FspBin, 'r+b')
+        self.FspDat = bytearray(hfsp.read())
+        hfsp.close()
+
+    def OutputStruct (self, obj, indent = 0):
+        max_key_len = 20
+        pstr = ('  ' * indent + '{0:<%d} = {1}\n') % max_key_len
+        if indent:
+            s = ''
+        else:
+            s = ('  ' * indent + '<%s>:\n') % obj.__class__.__name__
+        for field in obj._fields_:
+            key = field[0]
+            val = getattr(obj, key)
+            rep = ''
+            
+            if not isinstance(val, c_uint24) and isinstance(val, Structure):   
             
+                s += pstr.format(key, val.__class__.__name__)
+                s += self.OutputStruct (val, indent + 1)                
+            else:
+                if type(val) in (int, long):
+                    rep = hex(val)
+                elif isinstance(val, str) and (len(val) == 16):
+                    rep = str(uuid.UUID(bytes = val))
+                elif isinstance(val, c_uint24):                    
+                    rep = hex(val.get_value())
+                elif 'c_ubyte_Array' in str(type(val)):                
+                    rep = str(list(bytearray(val)))
+                else:
+                    rep = str(val)
+                s += pstr.format(key, rep)
+        return s
+    
+    def PrintFv (self):
+        print ("FV LIST:")
+        idx = 0
+        for (fvh, fvhe, offset) in self.FvList:            
+            guid = uuid.UUID(bytes = fvhe.FvName)
+            print ("FV%d FV GUID:%s  Offset:0x%08X  Length:0x%08X" % (idx, 
str(guid), offset, fvh.FvLength))
+            idx = idx + 1
+        print ("\nFSP LIST:")
+        for fsp in self.FspFv:
+            print "FSP%s contains FV%s" % (fsp, str(self.FspFv[fsp][1]))
+            print "\nFSP%s Info Header:" % fsp
+            fih = self.FspFv[fsp][0]            
+
+    def AlaignPtr (self, offset, alignment = 8):
+        return (offset + alignment - 1) & ~(alignment - 1)
+
+    def GetFspInfoHdr (self, fvh, fvhe, fvoffset):
+        if fvhe:
+            offset = fvh.ExtHeaderOffset + fvhe.ExtHeaderSize
+        else:
+            offset = fvh.HeaderLength
+        offset = self.AlaignPtr(offset)
+
+        # Now it should be 1st FFS
+        ffs = EFI_FFS_FILE_HEADER.from_buffer (self.FspDat, offset)        
+        offset += sizeof(ffs)
+        offset = self.AlaignPtr(offset)
+
+        # Now it should be 1st Section
+        sec = EFI_COMMON_SECTION_HEADER.from_buffer (self.FspDat, offset)
+        offset += sizeof(sec)
+
+        # Now it should be FSP_INFO_HEADER
+        offset += fvoffset
+        fih = FSP_INFORMATION_HEADER.from_buffer (self.FspDat, offset)
+        if 'FSPH' != bytearray.fromhex('%08X' % fih.Signature)[::-1]:
+            return None
+
+        return fih
+
+    def GetFvHdr (self, offset):
+        fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FspDat, offset)
+        if '_FVH' != bytearray.fromhex('%08X' % fvh.Signature)[::-1]:
+            return None, None
+        if fvh.ExtHeaderOffset > 0:
+            offset += fvh.ExtHeaderOffset
+            fvhe = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FspDat, 
offset)
+        else:
+            fvhe = None
+        return fvh, fvhe
+
+    def GetFvData(self, idx):
+        (fvh, fvhe, offset) = self.FvList[idx]
+        return self.FspDat[offset:offset+fvh.FvLength]
+
+    def CheckFsp (self):
+        if len(self.FspFv) == 0:
+            return
+
+        fih = None
+        for fv in self.FspFv:
+            if not fih:
+                fih = self.FspFv[fv][0]
+            else:
+                newfih = self.FspFv[fv][0]
+                if (newfih.ImageId != fih.ImageId) or (newfih.ImageRevision != 
fih.ImageRevision):
+                    raise Exception("Inconsistent FSP ImageId or ImageRevision 
detected !")
+        return
+
+    def WriteFsp(self, dir, name):
+        if not name:
+            name = self.FspBin
+        fspname, ext = os.path.splitext(os.path.basename(name))
+        for fv in self.FspFv:
+            filename = os.path.join(dir, fspname + fv + ext)
+            hfsp = open(filename, 'w+b')
+            for fvidx in self.FspFv[fv][1]:
+                hfsp.write (self.GetFvData(fvidx))
+            hfsp.close()
+
+    def WriteMap(self, dir, hfile):
+        if not hfile:
+            hfile = os.path.splitext(os.path.basename(self.FspBin))[0] + '.h'
+        fspname, ext = os.path.splitext(os.path.basename(hfile))
+        filename = os.path.join(dir, fspname + ext)
+        hfsp   = open(filename, 'w')
+        hfsp.write ('%s\n\n' % self.HeaderFile)
+
+        firstfv = True
+        for fsp in self.FspFv:
+            fih = self.FspFv[fsp][0]
+            fvs = self.FspFv[fsp][1]
+            if firstfv:
+                IdStr = str(bytearray.fromhex('%016X' % fih.ImageId)[::-1])
+                hfsp.write("#define  FSP_IMAGE_ID    0x%016X        /* '%s' 
*/\n" % (fih.ImageId, IdStr))
+                hfsp.write("#define  FSP_IMAGE_REV   0x%08X \n\n" % 
fih.ImageRevision)
+                firstfv = False
+            hfsp.write ('#define  FSP%s_BASE      0x%08X\n'   % (fsp, 
fih.ImageBase))
+            hfsp.write ('#define  FSP%s_OFFSET    0x%08X\n'   % (fsp, 
self.FvList[fvs[0]][-1]))
+            hfsp.write ('#define  FSP%s_LENGTH    0x%08X\n\n' % (fsp, 
fih.ImageSize))
+        hfsp.close()
+
+    def ParseFsp (self):
+        self.FspFv  = {}
+        flen = 0
+        for (fvh, fvhe, offset) in self.FvList:
+            fih = self.GetFspInfoHdr (fvh, fvhe, offset)
+            if fih:
+                if flen != 0:
+                    raise Exception("Incorrect FV size in image !")
+                ftype = str((fih.ImageAttribute >> 29) & 7)
+                if ftype not in self.FspNameDict:
+                    raise Exception("Unknown Attribute in image !")
+                fname = self.FspNameDict[str(ftype)]
+                if fname in self.FspFv:
+                    raise Exception("Multiple '%s' in image !" % fname)
+                self.FspFv[fname] = (copy.deepcopy(fih), [])
+                flen = fih.ImageSize
+            if flen > 0:
+                flen = flen - fvh.FvLength
+                if flen < 0:
+                    raise Exception("Incorrect FV size in image !")
+                self.FspFv[fname][1].append(self.FvList.index((fvh, fvhe, 
offset)))
+
+    def AddFv(self, offset):
+        fvh, fvhe = self.GetFvHdr (offset)
+        if fvh is None:
+            raise Exception('FV signature is not valid !')
+        fvitem = (copy.deepcopy(fvh), copy.deepcopy(fvhe), offset)
+        self.FvList.append(fvitem)
+        return fvh.FvLength
+
+    def ParseFv(self):
+        offset = 0
+        while (offset < len(self.FspDat)):
+            fv_len  = self.AddFv (offset)
+            offset += fv_len
+
+def GenFspHdr (fspfile, outdir, hfile, show):
+    fsp_fv = FspFv(fspfile)
+    fsp_fv.ParseFv()
+    fsp_fv.ParseFsp()
+    fsp_fv.CheckFsp()
+    if show:
+        fsp_fv.PrintFv()
+    fsp_fv.WriteMap(outdir, hfile)
+
+def SplitFspBin (fspfile, outdir, nametemplate, show):
+    fsp_fv = FspFv(fspfile)
+    fsp_fv.ParseFv()
+    fsp_fv.ParseFsp()
+    if show:
+        fsp_fv.PrintFv()
+    fsp_fv.WriteFsp(outdir, nametemplate)
+
+def main ():
+    parser = argparse.ArgumentParser()
+    subparsers    = parser.add_subparsers(title='commands')
+
+    parser_split  = subparsers.add_parser('split',  help='split a FSP into 
multiple components')
+    parser_split.set_defaults(which='split')
+    parser_split.add_argument('-f',  '--fspbin' , dest='FspBinary', type=str, 
help='FSP binary file path', required = True)
+    parser_split.add_argument('-o',  '--outdir' , dest='OutputDir', type=str, 
help='Output directory path',   default = '.')
+    parser_split.add_argument('-n',  '--nametpl', dest='NameTemplate', 
type=str, help='Output name template', default = '')
+    parser_split.add_argument('-p', action='store_true', help='Print FSP FV 
information', default = False)
+
+    parser_genhdr = subparsers.add_parser('genhdr',  help='generate a header 
file for FSP binary')
+    parser_genhdr.set_defaults(which='genhdr')
+    parser_genhdr.add_argument('-f',  '--fspbin' , dest='FspBinary', type=str, 
help='FSP binary file path', required = True)
+    parser_genhdr.add_argument('-o',  '--outdir' , dest='OutputDir', type=str, 
help='Output directory path',   default = '.')
+    parser_genhdr.add_argument('-n',  '--hfile',   dest='HFileName', type=str, 
help='Output header file name', default = '')
+    parser_genhdr.add_argument('-p', action='store_true', help='Print FSP FV 
information', default = False)
+
+    args = parser.parse_args()
+    if args.which in ['split', 'genhdr']:
+        if not os.path.exists(args.FspBinary):
+            raise Exception ("Could not locate FSP binary file '%s' !" % 
args.FspBinary)
+        if not os.path.exists(args.OutputDir):
+            raise Exception ("Invalid output directory '%s' !" % 
args.OutputDir)
+
+    if args.which == 'split':
+        SplitFspBin (args.FspBinary, args.OutputDir, args.NameTemplate, args.p)
+    elif args.which == 'genhdr':
+        GenFspHdr   (args.FspBinary, args.OutputDir, args.HFileName, args.p)
+    else:
+        pass
+
+    print 'Done!'
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/IntelFspPkg/Tools/GenCfgOpt.py b/IntelFspPkg/Tools/GenCfgOpt.py
index a38da70..a6c4bfe 100644
--- a/IntelFspPkg/Tools/GenCfgOpt.py
+++ b/IntelFspPkg/Tools/GenCfgOpt.py
@@ -1,6 +1,6 @@
 ## @ GenCfgOpt.py
 #
-# Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2014 - 2016, 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 that accompanies this 
distribution.
 # The full text of the license may be found at
@@ -88,48 +88,6 @@ are permitted provided that the following conditions are met:
 **/
 """
 
-def UpdateMemSiUpdInitOffsetValue (DscFile):
-    DscFd        = open(DscFile, "r")
-    DscLines     = DscFd.readlines()
-    DscFd.close()
-
-    DscContent = []
-    MemUpdInitOffset = 0
-    SiUpdInitOffset = 0
-    MemUpdInitOffsetValue = 0
-    SiUpdInitOffsetValue = 0
-
-    while len(DscLines):
-        DscLine  = DscLines.pop(0)
-        DscContent.append(DscLine)
-        DscLine = DscLine.strip()
-        Match = 
re.match("^([_a-zA-Z0-9]+).(MemoryInitUpdOffset)\s*\|\s*(0x[0-9A-F]+)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)",DscLine)
-        if Match:
-            MemUpdInitOffsetValue = int(Match.group(5), 0)
-        Match = 
re.match("^\s*([_a-zA-Z0-9]+).(SiliconInitUpdOffset)\s*\|\s*(0x[0-9A-F]+)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)",DscLine)
-        if Match:
-            SiUpdInitOffsetValue = int(Match.group(5), 0)
-        Match = 
re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(0x244450554D454D24)",DscLine)
-        if Match:
-            MemUpdInitOffset = int(Match.group(3), 0)
-        Match = 
re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(0x244450555F495324)",DscLine)
-        if Match:
-            SiUpdInitOffset = int(Match.group(3), 0)
-
-    if MemUpdInitOffsetValue != MemUpdInitOffset or SiUpdInitOffsetValue != 
SiUpdInitOffset:
-        MemUpdInitOffsetStr = "0x%08X" % MemUpdInitOffset
-        SiUpdInitOffsetStr = "0x%08X" % SiUpdInitOffset
-        DscFd = open(DscFile,"w")
-        for DscLine in DscContent:
-            Match = 
re.match("^\s*([_a-zA-Z0-9]+).(MemoryInitUpdOffset)\s*\|\s*(0x[0-9A-F]+)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)",DscLine)
-            if Match:
-                 DscLine = re.sub(r'(?:[^\s]+\s*$)', MemUpdInitOffsetStr + 
'\n', DscLine)
-            Match = 
re.match("^\s*([_a-zA-Z0-9]+).(SiliconInitUpdOffset)\s*\|\s*(0x[0-9A-F]+)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)",DscLine)
-            if Match:
-                 DscLine = re.sub(r'(?:[^\s]+\s*$)', SiUpdInitOffsetStr + 
'\n', line)
-            DscFd.writelines(DscLine)
-        DscFd.close()
-
 class CLogicalExpression:
     def __init__(self):
         self.index    = 0
@@ -331,6 +289,7 @@ class CGenCfgOpt:
     def __init__(self):
         self.Debug          = False
         self.Error          = ''
+        self.ReleaseMode    = True
 
         self._GlobalDataDef = """
 GlobalDataDef
@@ -347,7 +306,7 @@ EndList
 """
 
         self._BsfKeyList    = 
['FIND','NAME','HELP','TYPE','PAGE','OPTION','ORDER']
-        self._HdrKeyList    = ['HEADER','STRUCT', 'EMBED']
+        self._HdrKeyList    = ['HEADER','STRUCT', 'EMBED', 'COMMENT']
         self._BuidinOption  = {'$EN_DIS' : 'EN_DIS'}
 
         self._MacroDict   = {}
@@ -358,6 +317,13 @@ EndList
         self._FvDir       = ''
         self._MapVer      = 0
 
+    def ParseBuildMode (self, OutputStr):
+        if "RELEASE_" in OutputStr:
+            self.ReleaseMode = True
+        if "DEBUG_" in OutputStr:
+            self.ReleaseMode = False
+        return
+
     def ParseMacros (self, MacroDefStr):
         # ['-DABC=1', '-D', 'CFG_DEBUG=1', '-D', 'CFG_OUTDIR=Build']
         self._MacroDict = {}
@@ -445,7 +411,7 @@ EndList
         ConfigDict['value'] = newvalue
         return ""
 
-    def ParseDscFile (self, DscFile, FvDir):
+    def ParseDscFile (self, DscFile, FvDir, ConfigDscFile, ExtConfigDscFile):
         self._CfgItemList = []
         self._CfgPageDict = {}
         self._CfgBlkDict  = {}
@@ -475,20 +441,6 @@ EndList
                     IsDefSect = True
                     IsVpdSect = False
                     IsUpdSect = False
-                elif Match.group(1).lower() == "PcdsDynamicVpd".lower():
-                    ConfigDict = {}
-                    ConfigDict['header']  = 'ON'
-                    ConfigDict['region']  = 'VPD'
-                    ConfigDict['order']   = -1
-                    ConfigDict['page']    = ''
-                    ConfigDict['name']    = ''
-                    ConfigDict['find']    = ''
-                    ConfigDict['struct']  = ''
-                    ConfigDict['embed']   = ''
-                    ConfigDict['subreg']  = []
-                    IsDefSect = False
-                    IsVpdSect = True
-                    IsUpdSect = False
                 elif Match.group(1).lower() == "PcdsDynamicVpd.Upd".lower():
                     ConfigDict = {}
                     ConfigDict['header']  = 'ON'
@@ -499,6 +451,7 @@ EndList
                     ConfigDict['find']    = ''
                     ConfigDict['struct']  = ''
                     ConfigDict['embed']   = ''
+                    ConfigDict['comment'] = ''
                     ConfigDict['subreg']  = []
                     IsDefSect = False
                     IsUpdSect = True
@@ -537,7 +490,41 @@ EndList
                         else:
                             Match  = re.match("!(if|elseif)\s+(.+)", DscLine)
                             if Match:
-                                Result = self.EvaluateExpress(Match.group(2))
+                                IsFoundInFile = False
+                                MatchPcdFormat = 
re.match("^\s*(.+)\.(.+)\s*==\s*(.+)", Match.group(2))
+                                if MatchPcdFormat:
+                                       ExtConfigDsc = open(ExtConfigDscFile, 
"r")
+                                       ExtConfigDscLines = 
ExtConfigDsc.readlines()
+                                       ExtConfigDsc.close()
+                                       
+                                       while len(ExtConfigDscLines):
+                                           ExtConfigDscLine  = 
ExtConfigDscLines.pop(0).strip()
+                                           MatchExtConfigPcd = 
re.match("^\s*(.+)\s*\|\s*(.+)", ExtConfigDscLine)
+                                           if MatchExtConfigPcd and 
IsFoundInFile == False:
+                                                 PcdFormatStr = 
str(str(MatchPcdFormat.group(1)) + "." + str(MatchPcdFormat.group(2)))
+                                                 ExtConfigPcd = 
str(MatchExtConfigPcd.group(1))
+                                                 Result = False
+                                                 if PcdFormatStr.strip() == 
ExtConfigPcd.strip():
+                                                       Result = 
self.EvaluateExpress(str(str(MatchExtConfigPcd.group(2)) + " == " + 
str(MatchPcdFormat.group(3))))
+                                                       IsFoundInFile = True
+                                                       break
+                                       if IsFoundInFile == False:
+                                           ConfigDsc = open(ConfigDscFile, "r")
+                                           ConfigDscLines = 
ConfigDsc.readlines()
+                                           ConfigDsc.close()
+                                           while len(ConfigDscLines):
+                                               ConfigDscLine  = 
ConfigDscLines.pop(0).strip()
+                                               MatchConfigPcd = 
re.match("^\s*(.+)\s*\|\s*(.+)", ConfigDscLine)
+                                               if MatchConfigPcd:
+                                                     PcdFormatStr = 
str(str(MatchPcdFormat.group(1)) + "." + str(MatchPcdFormat.group(2)))
+                                                     ConfigPcd = 
str(MatchConfigPcd.group(1))
+                                                     Result = False
+                                                     if PcdFormatStr.strip() 
== ConfigPcd.strip():
+                                                           Result = 
self.EvaluateExpress(str(str(MatchConfigPcd.group(2)) + " == " + 
str(MatchPcdFormat.group(3))))
+                                                           IsFoundInFile = True
+                                                           break
+                                else:
+                                       Result = 
self.EvaluateExpress(Match.group(2))
                                 if Match.group(1) == "if":
                                     ElifStack.append(0)
                                     IfStack.append(Result)
@@ -575,17 +562,20 @@ EndList
                 continue
 
             if IsDefSect:
-                #DEFINE UPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E09
+                #DEFINE UPD_TOOL_GUID       = 
8C3D856A-9BE6-468E-850A-24F7A8D38E09
+                #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)
                 if Match:
                     self._MacroDict[Match.group(1)] = Match.group(2)
                     if self.Debug:
                         print "INFO : DEFINE %s = [ %s ]" % (Match.group(1), 
Match.group(2))
             else:
-                Match = re.match("^\s*#\s+!(BSF|HDR)\s+(.+)", DscLine)
+                Match = re.match("^\s*#\s+(!BSF|@Bsf|!HDR)\s+(.+)", DscLine)
                 if Match:
                     Remaining = Match.group(2)
-                    if Match.group(1) == 'BSF':
+                    if Match.group(1) == '!BSF' or Match.group(1) == '@Bsf':
                         Match = re.match("(?:^|.+\s+)PAGES:{(.+?)}", Remaining)
                         if Match:
                             # !BSF PAGES:{HSW:"Haswell System Agent", 
LPT:"Lynx Point PCH"}
@@ -613,6 +603,37 @@ EndList
                             if Match:
                                 ConfigDict[Key.lower()]  = Match.group(1)
 
+                Match = re.match("^\s*#\s+@Prompt\s+(.+)", DscLine)
+                if Match:
+                    ConfigDict['name'] = Match.group(1)
+
+                Match = 
re.match("^\s*#\s*@ValidList\s*(.+)\s*\|\s*(.+)\s*\|\s*(.+)\s*", DscLine)
+                if Match:
+                    if Match.group(2).strip() in self._BuidinOption:
+                        ConfigDict['option'] = Match.group(2).strip()
+                    else:
+                        OptionValueList = Match.group(2).split(',')
+                        OptionStringList = Match.group(3).split(',')
+                        Index = 0
+                        for Option in OptionValueList:
+                             Option = Option.strip()
+                             ConfigDict['option'] = ConfigDict['option'] + 
str(Option) + ':' + OptionStringList[Index].strip()
+                             Index += 1
+                             if Index in range(len(OptionValueList)):
+                                 ConfigDict['option'] += ', '
+                    ConfigDict['type'] = "Combo"
+
+                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))
+                    else:
+                       ConfigDict['type'] = "EditNum, DEC, (%s,%s)" % 
(Match.group(2), Match.group(3))
+
+                Match = re.match("^\s*##\s+(.+)", DscLine)
+                if Match:
+                    ConfigDict['help'] = Match.group(1)
+
                 # Check VPD/UPD
                 if IsUpdSect:
                     Match = 
re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)",DscLine)
@@ -666,16 +687,20 @@ EndList
                     ConfigDict['find']   = ''
                     ConfigDict['struct'] = ''
                     ConfigDict['embed']  = ''
+                    ConfigDict['comment'] = ''
                     ConfigDict['order']  = -1
                     ConfigDict['subreg'] = []
+                    ConfigDict['option'] = ''
                 else:
                     # It could be a virtual item as below
                     # !BSF FIELD:{1:SerialDebugPortAddress0}
-                    Match = re.match("^\s*#\s+!BSF\s+FIELD:{(.+):(\d+)}", 
DscLine)
+                    # or
+                    # @Bsf FIELD:{1:SerialDebugPortAddress0}
+                    Match = 
re.match("^\s*#\s+(!BSF|@Bsf)\s+FIELD:{(.+):(\d+)}", DscLine)
                     if Match:
                         SubCfgDict = ConfigDict
-                        SubCfgDict['cname']  = Match.group(1)
-                        SubCfgDict['length'] = int (Match.group(2))
+                        SubCfgDict['cname']  = Match.group(2)
+                        SubCfgDict['length'] = int (Match.group(3))
                         if SubCfgDict['length'] > 0:
                             LastItem =  self._CfgItemList[-1]
                             if len(LastItem['subreg']) == 0:
@@ -723,107 +748,132 @@ EndList
                     SubItem['value'] = '{%s}' % valuestr
         return Error
 
-    def UpdateVpdSizeField (self):
-        FvDir = self._FvDir;
-
-        if 'VPD_TOOL_GUID' not in self._MacroDict:
-            self.Error = "VPD_TOOL_GUID definition is missing in DSC file"
-            return 1
-
-        VpdMapFile = os.path.join(FvDir, self._MacroDict['VPD_TOOL_GUID'] + 
'.map')
-        if not os.path.exists(VpdMapFile):
-            self.Error = "VPD MAP file '%s' does not exist" % VpdMapFile
-            return 2
-
-        MapFd       = open(VpdMapFile, "r")
-        MapLines    = MapFd.readlines()
-        MapFd.close()
-
-        VpdDict  = {}
-        PcdDict  = {}
-        for MapLine in MapLines:
-            #gPlatformFspPkgTokenSpaceGuid.PcdVpdRegionSign | DEFAULT | 0x0000 
| 8 | 0x534450565F425346
-            #gPlatformFspPkgTokenSpaceGuid.PcdVpdRegionSign | 0x0000 | 8 | 
0x534450565F425346
-            #gPlatformFspPkgTokenSpaceGuid.PcdTest          | 0x0008 | 5 | 
{0x01,0x02,0x03,0x04,0x05}
-            Match = 
re.match("([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)(\s\|\sDEFAULT)?\s\|\s(0x[0-9A-F]{4})\s\|\s(\d+|0x[0-9a-fA-F]+)\s\|\s(\{?[x0-9a-fA-F,\s]+\}?)",
 MapLine)
-            if Match:
-                Space  = Match.group(1)
-                Name   = Match.group(2)
-                if (self._MapVer == 0) and (Match.group(3) != None):
-                    self._MapVer = 1
-                Offset = int (Match.group(4), 16)
-                if Match.group(5).startswith("0x"):
-                    Length = int (Match.group(5), 16)
-                else :
-                    Length = int (Match.group(5))
-                PcdDict["len"]   = Length
-                PcdDict["value"]   = Match.group(6)
-                VpdDict[Space+'.'+Name] = dict(PcdDict)
-
-        for Item in self._CfgItemList:
-            if Item['value'] == '':
-                Item['value']  = 
VpdDict[Item['space']+'.'+Item['cname']]['value']
-            if Item['length'] == -1:
-                Item['length'] = 
VpdDict[Item['space']+'.'+Item['cname']]['len']
-            if Item['struct'] != '':
-                Type = Item['struct'].strip()
-                if Type.endswith('*') and (Item['length'] != 4):
-                    self.Error = "Struct pointer '%s' has invalid size" % Type
-                    return 3
-
-        return 0
-
-    def CreateUpdTxtFile (self, UpdTxtFile):
-        FvDir = self._FvDir
-        if 'UPD_TOOL_GUID' not in self._MacroDict:
-            self.Error = "UPD_TOOL_GUID definition is missing in DSC file"
-            return 1
+    def CreateSplitUpdTxt (self, UpdTxtFile):
+        GuidList = 
['FSP_T_UPD_TOOL_GUID','FSP_M_UPD_TOOL_GUID','FSP_S_UPD_TOOL_GUID']
+        SignatureList = ['0x4450555F54505346', 
'0x4450555F4D505346','0x4450555F53505346']        #  FSPT_UPD, FSPM_UPD, and 
FSPS_UPD
+        for Index in range(len(GuidList)):
+            UpdTxtFile = ''
+            FvDir = self._FvDir
+            if GuidList[Index] not in self._MacroDict:
+                self.Error = "%s definition is missing in DSC file" % 
(GuidList[Index])
+                return 1
 
-        if UpdTxtFile == '':
-            UpdTxtFile = os.path.join(FvDir, self._MacroDict['UPD_TOOL_GUID'] 
+ '.txt')
+            if UpdTxtFile == '':
+                UpdTxtFile = os.path.join(FvDir, 
self._MacroDict[GuidList[Index]] + '.txt')
 
-        ReCreate = False
-        if not os.path.exists(UpdTxtFile):
-            ReCreate = True
-        else:
-            DscTime = os.path.getmtime(self._DscFile)
-            TxtTime = os.path.getmtime(UpdTxtFile)
-            if DscTime > TxtTime:
+            ReCreate = False
+            if not os.path.exists(UpdTxtFile):
                 ReCreate = True
+            else:
+                DscTime = os.path.getmtime(self._DscFile)
+                TxtTime = os.path.getmtime(UpdTxtFile)
+                if DscTime > TxtTime:
+                    ReCreate = True
 
-        if not  ReCreate:
-            # DSC has not been modified yet
-            # So don't have to re-generate other files
-            self.Error = 'No DSC file change, skip to create UPD TXT file'
-            return 256
+            if not  ReCreate:
+                # DSC has not been modified yet
+                # So don't have to re-generate other files
+                self.Error = 'No DSC file change, skip to create UPD TXT file'
+                return 256
 
-        TxtFd = open(UpdTxtFile, "w")
-        TxtFd.write("%s\n"   % (__copyright_txt__ % date.today().year))
+            TxtFd = open(UpdTxtFile, "w")
+            TxtFd.write("%s\n"   % (__copyright_txt__ % date.today().year))
 
-        NextOffset = 0
-        SpaceIdx   = 0
-        if self._MapVer == 1:
+            NextOffset = 0
+            SpaceIdx   = 0
+            StartAddr  = 0
+            EndAddr    = 0
             Default = 'DEFAULT|'
-        else:
-            Default = ''
-        for Item in self._CfgItemList:
-            if Item['region'] != 'UPD':
-                continue
-            Offset = Item['offset']
-            if NextOffset < Offset:
-                # insert one line
-                TxtFd.write("%s.UnusedUpdSpace%d|%s0x%04X|0x%04X|{0}\n" % 
(Item['space'], SpaceIdx, Default, NextOffset, Offset - NextOffset))
-                SpaceIdx = SpaceIdx + 1
-            NextOffset = Offset + Item['length']
-            TxtFd.write("%s.%s|%s0x%04X|%s|%s\n" % 
(Item['space'],Item['cname'],Default,Item['offset'],Item['length'],Item['value']))
-        TxtFd.close()
+            InRange = False
+            for Item in self._CfgItemList:
+                if Item['cname'] == 'Signature' and str(Item['value']) == 
SignatureList[Index]:
+                    StartAddr = Item['offset']
+                    NextOffset = StartAddr
+                    InRange = True
+                if Item['cname'] == 'UpdTerminator' and InRange == True:
+                    EndAddr = Item['offset']
+                    InRange = False
+            InRange = False
+            for Item in self._CfgItemList:
+                if Item['cname'] == 'Signature' and str(Item['value']) == 
SignatureList[Index]:
+                    InRange = True
+                if InRange != True:
+                    continue
+                if Item['cname'] == 'UpdTerminator':
+                    InRange = False
+                if Item['region'] != 'UPD':
+                    continue
+                Offset = Item['offset']
+                if StartAddr > Offset or EndAddr < Offset:
+                    continue
+                if NextOffset < Offset:
+                    # insert one line
+                    TxtFd.write("%s.UnusedUpdSpace%d|%s0x%04X|0x%04X|{0}\n" % 
(Item['space'], SpaceIdx, Default, NextOffset - StartAddr, Offset - NextOffset))
+                    SpaceIdx = SpaceIdx + 1
+                NextOffset = Offset + Item['length']
+                if Item['cname'] == 'PcdSerialIoUartDebugEnable':
+                    if self.ReleaseMode == False:
+                        Item['value'] = 0x01
+                TxtFd.write("%s.%s|%s0x%04X|%s|%s\n" % 
(Item['space'],Item['cname'],Default,Item['offset'] - 
StartAddr,Item['length'],Item['value']))
+            TxtFd.close()
         return 0
 
-    def CreateField (self, Item, Name, Length, Offset, Struct, BsfName, Help):
+    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
+                                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):
         PosName    = 28
         PosComment = 30
         NameLine=''
         HelpLine=''
+        OptionLine=''
 
         IsArray = False
         if Length in [1,2,4,8]:
@@ -854,17 +904,22 @@ EndList
             Space1 = 1
 
         if BsfName != '':
-            NameLine="    %s\n" % BsfName
+            NameLine=" - %s\n" % BsfName
+        else:
+            NameLine="\n"
 
         if Help != '':
-            HelpLine="    %s\n" % Help
+            HelpLine = self.ProcessMultilines (Help, 80)
+
+        if Option != '':
+            OptionLine = self.ProcessMultilines (Option, 80)
 
         if Offset is None:
             OffsetStr = '????'
         else:
             OffsetStr = '0x%04X' % Offset
 
-        return "/** Offset %s\n%s%s**/\n  %s%s%s;\n" % (OffsetStr, NameLine, 
HelpLine, Type, ' ' * Space1, Name,)
+        return "\n/** Offset %s%s%s%s**/\n  %s%s%s;\n" % (OffsetStr, NameLine, 
HelpLine, OptionLine, Type, ' ' * Space1, Name,)
 
     def PostProcessBody (self, TextBody):
         NewTextBody = []
@@ -872,13 +927,32 @@ EndList
         IncludeLine = False
         StructName  = ''
         VariableName = ''
+        IsUpdHdrDefined = False
+        IsUpdHeader = False
         for Line in TextBody:
+           SplitToLines = Line.splitlines()
+           MatchComment = 
re.match("^/\*\sCOMMENT:(\w+):([\w|\W|\s]+)\s\*/\s([\s\S]*)", SplitToLines[0])
+           if MatchComment:
+              if MatchComment.group(1) == 'FSP_UPD_HEADER':
+                  IsUpdHeader = True
+              else:
+                  IsUpdHeader = False
+              if IsUpdHdrDefined != True or IsUpdHeader != True:
+                CommentLine = " " + MatchComment.group(2) + "\n"
+                NewTextBody.append("/**" + CommentLine + "**/\n")
+              Line = Line[(len(SplitToLines[0]) + 1):]
+
            Match = 
re.match("^/\*\sEMBED_STRUCT:(\w+):(\w+):(START|END)\s\*/\s([\s\S]*)", Line)
            if Match:
                Line = Match.group(4)
+               if Match.group(1) == 'FSP_UPD_HEADER':
+                   IsUpdHeader = True
+               else:
+                   IsUpdHeader = False
 
            if Match and Match.group(3) == 'START':
-               NewTextBody.append ('typedef struct {\n')
+               if IsUpdHdrDefined != True or IsUpdHeader != True:
+                   NewTextBody.append ('typedef struct {\n')
                StructName   = Match.group(1)
                VariableName = Match.group(2)
                MatchOffset = re.search('/\*\*\sOffset\s0x([a-fA-F0-9]+)', Line)
@@ -888,9 +962,10 @@ EndList
                    Offset = None
                Line
                IncludeLine = True
-               OldTextBody.append (self.CreateField (None, VariableName, 0, 
Offset, StructName, '', ''))
+               OldTextBody.append (self.CreateField (None, VariableName, 0, 
Offset, StructName, '', '', ''))
            if IncludeLine:
-               NewTextBody.append (Line)
+               if IsUpdHdrDefined != True or IsUpdHeader != True:
+                   NewTextBody.append (Line)
            else:
                OldTextBody.append (Line)
 
@@ -898,37 +973,21 @@ EndList
                if (StructName != Match.group(1)) or (VariableName != 
Match.group(2)):
                    print "Unmatched struct name '%s' and '%s' !"  % 
(StructName, Match.group(1))
                else:
-                   NewTextBody.append ('} %s;\n\n' %  StructName)
+                   if IsUpdHdrDefined != True or IsUpdHeader != True:
+                      NewTextBody.append ('} %s;\n\n' %  StructName)
+                      IsUpdHdrDefined = True
                IncludeLine = False
         NewTextBody.extend(OldTextBody)
         return NewTextBody
 
-    def CreateHeaderFile (self, InputHeaderFile, IsInternal):
+    def CreateHeaderFile (self, InputHeaderFile):
         FvDir = self._FvDir
 
-        if IsInternal:
-            HeaderFile = os.path.join(FvDir, 'FspUpdVpdInternal.h')
-        else:
-            HeaderFile = os.path.join(FvDir, 'FspUpdVpd.h')
+        HeaderFileName = 'FspUpd.h'
+        HeaderFile = os.path.join(FvDir, HeaderFileName)
 
         # Check if header needs to be recreated
         ReCreate = False
-        if IsInternal:
-            if not os.path.exists(HeaderFile):
-                ReCreate = True
-            else:
-                DscTime  = os.path.getmtime(self._DscFile)
-                HeadTime = os.path.getmtime(HeaderFile)
-                if not os.path.exists(InputHeaderFile):
-                    InpTime =  HeadTime
-                else:
-                    InpTime  = os.path.getmtime(InputHeaderFile)
-                if DscTime > HeadTime or InpTime > HeadTime:
-                    ReCreate = True
-
-            if not ReCreate:
-                self.Error = "No DSC or input header file is changed, skip the 
header file generating"
-                return 256
 
         TxtBody = []
         for Item in self._CfgItemList:
@@ -939,51 +998,60 @@ EndList
                    Chars.append(chr(Value & 0xFF))
                    Value = Value >> 8
                SignatureStr = ''.join(Chars)
-               if int(Item['offset']) == 0:
-                   TxtBody.append("#define FSP_UPD_SIGNATURE                %s 
       /* '%s' */\n" % (Item['value'], SignatureStr))
-               elif 'MEM' in SignatureStr:
-                   TxtBody.append("#define FSP_MEMORY_INIT_UPD_SIGNATURE    %s 
       /* '%s' */\n" % (Item['value'], SignatureStr))
-               else:
-                   TxtBody.append("#define FSP_SILICON_INIT_UPD_SIGNATURE   %s 
       /* '%s' */\n" % (Item['value'], SignatureStr))
+               if 'FSPT' in SignatureStr:
+                   TxtBody.append("#define FSPT_UPD_SIGNATURE               %s 
       /* '%s' */\n\n" % (Item['value'], SignatureStr))
+               elif 'FSPM' in SignatureStr:
+                   TxtBody.append("#define FSPM_UPD_SIGNATURE               %s 
       /* '%s' */\n\n" % (Item['value'], SignatureStr))
+               elif 'FSPS' in SignatureStr:
+                   TxtBody.append("#define FSPS_UPD_SIGNATURE               %s 
       /* '%s' */\n\n" % (Item['value'], SignatureStr))
         TxtBody.append("\n")
 
-        for Region in ['UPD', 'VPD']:
-
-            # Write  PcdVpdRegionSign and PcdImageRevision
-            if Region[0] == 'V':
-                if 'VPD_TOOL_GUID' not in self._MacroDict:
-                    self.Error = "VPD_TOOL_GUID definition is missing in DSC 
file"
-                    return 1
-
-                BinFile = os.path.join(FvDir, self._MacroDict['VPD_TOOL_GUID'] 
+ ".bin")
-                if not os.path.exists(BinFile):
-                    self.Error = "VPD binary file '%s' does not exist" % 
BinFile
-                    return 2
-
-                BinFd = open(BinFile, "rb")
-                IdStr    = BinFd.read(0x08)
-                ImageId  = struct.unpack('<Q', IdStr)
-                ImageRev = struct.unpack('<I', BinFd.read(0x04))
-                BinFd.close()
-
-                TxtBody.append("#define FSP_IMAGE_ID    0x%016X        /* '%s' 
*/\n" % (ImageId[0], IdStr))
-                TxtBody.append("#define FSP_IMAGE_REV   0x%08X \n\n" % 
ImageRev[0])
-
-            TxtBody.append("typedef struct _" + Region[0]  + "PD_DATA_REGION 
{\n")
-            NextOffset  = 0
-            SpaceIdx    = 0
-            Offset      = 0
-
-            LastVisible = True
-            ResvOffset  = 0
-            ResvIdx     = 0
-            LineBuffer  = []
+        for Region in ['UPD']:
+            UpdOffsetTable = []
+            UpdSignature = ['0x4450555F54505346', '0x4450555F4D505346', 
'0x4450555F53505346']   #['FSPT_UPD', 'FSPM_UPD', 'FSPS_UPD']
+            UpdStructure = ['FSPT_UPD', 'FSPM_UPD', 'FSPS_UPD']
             for Item in self._CfgItemList:
-                if Item['region'] != Region:
-                    continue
+                if Item["cname"] == 'Signature' and Item["value"] in 
UpdSignature:
+                    UpdOffsetTable.append (Item["offset"])
+
+            for UpdIdx in range(len(UpdOffsetTable)):
+                CommentLine = ""
+                for Item in self._CfgItemList:
+                    if Item["comment"] != '' and Item["offset"] >= 
UpdOffsetTable[UpdIdx]:
+                        MatchComment = 
re.match("^(U|V)PD_DATA_REGION:([\w|\W|\s]+)", Item["comment"])
+                        if MatchComment and MatchComment.group(1) == Region[0]:
+                            CommentLine = " " + MatchComment.group(2) + "\n"
+                            TxtBody.append("/**" + CommentLine + "**/\n")
+                    elif Item["offset"] >= UpdOffsetTable[UpdIdx] and 
Item["comment"] == '':
+                        Match = re.match("^FSP([\w|\W|\s])_UPD", 
UpdStructure[UpdIdx])
+                        if Match:
+                            TxtBody.append("/** Fsp " + Match.group(1) + " UPD 
Configuration\n**/\n")
+                TxtBody.append("typedef struct {\n")
+                NextOffset  = 0
+                SpaceIdx    = 0
+                Offset      = 0
+
+                LastVisible = True
+                ResvOffset  = 0
+                ResvIdx     = 0
+                LineBuffer  = []
+                InRange = False
+                for Item in self._CfgItemList:
+                    if Item['cname'] == 'Signature' and str(Item['value']) == 
UpdSignature[UpdIdx] or Region[0] == 'V':
+                        InRange = True
+                    if InRange != True:
+                        continue
+                    if Item['cname'] == 'UpdTerminator':
+                        InRange = False
+
+                    if Item['region'] != Region:
+                        continue
+
+                    if Item["offset"] < UpdOffsetTable[UpdIdx]:
+                        continue
+
+                    NextVisible = LastVisible
 
-                NextVisible = LastVisible
-                if not IsInternal:
                     if LastVisible and (Item['header'] == 'OFF'):
                         NextVisible = False
                         ResvOffset  = Item['offset']
@@ -991,50 +1059,53 @@ EndList
                         NextVisible = True
                         Name = "Reserved" + Region[0] + "pdSpace%d" % ResvIdx
                         ResvIdx = ResvIdx + 1
-                        TxtBody.append(self.CreateField (Item, Name, 
Item["offset"] - ResvOffset, ResvOffset, '', '', ''))
-
-                if  Offset < Item["offset"]:
-                    if IsInternal or LastVisible:
-                        Name = "Unused" + Region[0] + "pdSpace%d" % SpaceIdx
-                        LineBuffer.append(self.CreateField (Item, Name, 
Item["offset"] - Offset, Offset, '', '', ''))
-                    SpaceIdx = SpaceIdx + 1
-                    Offset   = Item["offset"]
-
-                if Offset != Item["offset"]:
-                    self.Error = "Unsorted offset 0x%04X\n" % Item["offset"]
-                    return 3                    
-
-                LastVisible = NextVisible
-
-                Offset = Offset + Item["length"]
-                if IsInternal or LastVisible:
-                    for Each in LineBuffer:
-                        TxtBody.append (Each)
-                    LineBuffer = []
-                    Embed = Item["embed"].upper()
-                    if Embed.endswith(':START') or Embed.endswith(':END'):
-                        Marker = '/* EMBED_STRUCT:%s */ ' % Item["embed"]
-                    else:
-                        if Embed == '':
-                            Marker = '';
+                        TxtBody.append(self.CreateField (Item, Name, 
Item["offset"] - ResvOffset, ResvOffset, '', '', '', ''))
+
+                    if  Offset < Item["offset"]:
+                        if LastVisible:
+                            Name = "Unused" + Region[0] + "pdSpace%d" % 
SpaceIdx
+                            LineBuffer.append(self.CreateField (Item, Name, 
Item["offset"] - Offset, Offset, '', '', '', ''))
+                        SpaceIdx = SpaceIdx + 1
+                        Offset   = Item["offset"]
+
+                    LastVisible = NextVisible
+
+                    Offset = Offset + Item["length"]
+                    if LastVisible:
+                        for Each in LineBuffer:
+                            TxtBody.append (Each)
+                        LineBuffer = []
+                        Comment = Item["comment"]
+                        Embed = Item["embed"].upper()
+                        if Embed.endswith(':START') or Embed.endswith(':END'):
+                            if not Comment == '' and Embed.endswith(':START'):
+                               Marker = '/* COMMENT:%s */ \n' % Item["comment"]
+                               Marker = Marker + '/* EMBED_STRUCT:%s */ ' % 
Item["embed"]
+                            else:
+                               Marker = '/* EMBED_STRUCT:%s */ ' % 
Item["embed"]
                         else:
-                            self.Error = "Invalid embedded structure format 
'%s'!\n" % Item["embed"]
-                            return 4
-                    Line = Marker + self.CreateField (Item, Item["cname"], 
Item["length"], Item["offset"], Item['struct'], Item['name'], Item['help'])
-                    TxtBody.append(Line)
-                    
-            TxtBody.append("} " + Region[0] + "PD_DATA_REGION;\n\n")
+                            if Embed == '':
+                                Marker = '';
+                            else:
+                                self.Error = "Invalid embedded structure 
format '%s'!\n" % Item["embed"]
+                                return 4
+                        Line = Marker + self.CreateField (Item, Item["cname"], 
Item["length"], Item["offset"], Item['struct'], Item['name'], Item['help'], 
Item['option'])
+                        TxtBody.append(Line)
+                    if Item['cname'] == 'UpdTerminator':
+                        break
+                TxtBody.append("} " + UpdStructure[UpdIdx] + ";\n\n")
         
         # Handle the embedded data structure
         TxtBody = self.PostProcessBody (TxtBody)
 
-        HeaderFd = open(HeaderFile, "w")
-        FileBase = os.path.basename(HeaderFile)
-        FileName = FileBase.replace(".", "_").upper()
-        HeaderFd.write("%s\n"   % (__copyright_h__ % date.today().year))
-        HeaderFd.write("#ifndef __%s__\n"   % FileName)
-        HeaderFd.write("#define __%s__\n\n" % FileName)
-        HeaderFd.write("#pragma pack(1)\n\n")
+        HeaderTFileName = 'FsptUpd.h'
+        HeaderMFileName = 'FspmUpd.h'
+        HeaderSFileName = 'FspsUpd.h'
+
+        UpdRegionCheck = ['FSPT', 'FSPM', 'FSPS']     # FSPX_UPD_REGION
+        UpdConfigCheck = ['FSP_T', 'FSP_M', 'FSP_S']  # FSP_X_CONFIG, 
FSP_X_TEST_CONFIG, FSP_X_RESTRICTED_CONFIG
+        UpdSignatureCheck = ['FSPT_UPD_SIGNATURE', 'FSPM_UPD_SIGNATURE', 
'FSPS_UPD_SIGNATURE']
+        ExcludedSpecificUpd = 'FSPM_ARCH_UPD'
 
         if InputHeaderFile != '':
             if not os.path.exists(InputHeaderFile):
@@ -1045,11 +1116,28 @@ EndList
             IncLines     = InFd.readlines()
             InFd.close()
 
+        for item in range(len(UpdRegionCheck)):
+            if UpdRegionCheck[item] == 'FSPT':
+                HeaderFd = open(os.path.join(FvDir, HeaderTFileName), "w")
+                FileBase = os.path.basename(os.path.join(FvDir, 
HeaderTFileName))
+            elif UpdRegionCheck[item] == 'FSPM':
+                HeaderFd = open(os.path.join(FvDir, HeaderMFileName), "w")
+                FileBase = os.path.basename(os.path.join(FvDir, 
HeaderMFileName))
+            elif UpdRegionCheck[item] == 'FSPS':
+                HeaderFd = open(os.path.join(FvDir, HeaderSFileName), "w")
+                FileBase = os.path.basename(os.path.join(FvDir, 
HeaderSFileName))
+            FileName = FileBase.replace(".", "_").upper()
+            HeaderFd.write("%s\n"   % (__copyright_h__ % date.today().year))
+            HeaderFd.write("#ifndef __%s__\n"   % FileName)
+            HeaderFd.write("#define __%s__\n\n" % FileName)
+            HeaderFd.write("#include <%s>\n\n" % HeaderFileName)
+            HeaderFd.write("#pragma pack(push, 1)\n\n")
+
             Export = False
             for Line in IncLines:
-                Match = re.search 
("!EXPORT\s+EXTERNAL_BOOTLOADER_STRUCT_(BEGIN|END)\s+", Line)
+                Match = re.search 
("!EXPORT\s+([A-Z]+)\s+EXTERNAL_BOOTLOADER_STRUCT_(BEGIN|END)\s+", Line)
                 if Match:
-                    if Match.group(1) == "BEGIN":
+                    if Match.group(2) == "BEGIN" and Match.group(1) == 
UpdRegionCheck[item]:
                         Export = True
                         continue
                     else:
@@ -1057,11 +1145,86 @@ EndList
                         continue
                 if Export:
                     HeaderFd.write(Line)
-            HeaderFd.write("\n\n")
-            
-        for Line in TxtBody:
-            HeaderFd.write (Line)
-        HeaderFd.write("#pragma pack()\n\n")
+            HeaderFd.write("\n")
+
+            Index = 0
+            StartIndex = 0
+            EndIndex = 0
+            StructStart = []
+            StructStartWithComment = []
+            StructEnd = []
+            for Line in TxtBody:
+                Index += 1
+                Match = re.match("(typedef struct {)", Line)
+                if Match:
+                    StartIndex = Index - 1
+                Match = re.match("}\s([_A-Z0-9]+);", Line)
+                if Match and (UpdRegionCheck[item] in Match.group(1) or 
UpdConfigCheck[item] in Match.group(1)) and (ExcludedSpecificUpd not in 
Match.group(1)):
+                    EndIndex = Index
+                    StructStart.append(StartIndex)
+                    StructEnd.append(EndIndex)
+            Index = 0
+            for Line in TxtBody:
+                Index += 1
+                for Item in range(len(StructStart)):
+                    if Index == StructStart[Item]:
+                        Match = re.match("^(/\*\*\s*)", Line)
+                        if Match:
+                            StructStartWithComment.append(StructStart[Item])
+                        else:
+                            StructStartWithComment.append(StructStart[Item] + 
1)
+            Index = 0
+            for Line in TxtBody:
+                Index += 1
+                for Item in range(len(StructStart)):
+                    if Index >= StructStartWithComment[Item] and Index <= 
StructEnd[Item]:
+                        HeaderFd.write (Line)
+            HeaderFd.write("#pragma pack(pop)\n\n")
+            HeaderFd.write("#endif\n")
+            HeaderFd.close()
+
+        HeaderFd = open(HeaderFile, "w")
+        FileBase = os.path.basename(HeaderFile)
+        FileName = FileBase.replace(".", "_").upper()
+        HeaderFd.write("%s\n"   % (__copyright_h__ % date.today().year))
+        HeaderFd.write("#ifndef __%s__\n"   % FileName)
+        HeaderFd.write("#define __%s__\n\n" % FileName)
+        HeaderFd.write("#include <FspApi.h>\n\n")
+        HeaderFd.write("#pragma pack(push, 1)\n\n")
+
+        for item in range(len(UpdRegionCheck)):
+            Index = 0
+            StartIndex = 0
+            EndIndex = 0
+            StructStart = []
+            StructStartWithComment = []
+            StructEnd = []
+            for Line in TxtBody:
+                Index += 1
+                Match = re.match("(typedef struct {)", Line)
+                if Match:
+                    StartIndex = Index - 1
+                Match = re.match("#define\s([_A-Z0-9]+)\s*", Line)
+                if Match and (UpdSignatureCheck[item] in Match.group(1) or 
UpdSignatureCheck[item] in Match.group(1)):
+                    StructStart.append(Index - 1)
+                    StructEnd.append(Index)
+            Index = 0
+            for Line in TxtBody:
+                Index += 1
+                for Item in range(len(StructStart)):
+                    if Index == StructStart[Item]:
+                        Match = re.match("^(/\*\*\s*)", Line)
+                        if Match:
+                            StructStartWithComment.append(StructStart[Item])
+                        else:
+                            StructStartWithComment.append(StructStart[Item] + 
1)
+            Index = 0
+            for Line in TxtBody:
+                Index += 1
+                for Item in range(len(StructStart)):
+                    if Index >= StructStartWithComment[Item] and Index <= 
StructEnd[Item]:
+                        HeaderFd.write (Line)
+        HeaderFd.write("#pragma pack(pop)\n\n")
         HeaderFd.write("#endif\n")
         HeaderFd.close()
 
@@ -1233,56 +1396,50 @@ def Main():
         if not os.path.exists(DscFile):
             print "ERROR: Cannot open DSC file '%s' !" % DscFile
             return 2
-
-        UpdateMemSiUpdInitOffsetValue(DscFile)
+        ConfigDscFile = sys.argv[4]
+        if not os.path.exists(ConfigDscFile):
+            print "ERROR: Cannot open Config DSC file '%s' !" % ConfigDscFile
+            return 2
+        ExtConfigDscFile = sys.argv[5]
+        if not os.path.exists(ExtConfigDscFile):
+            print "ERROR: Cannot open Ext Config DSC file '%s' !" % 
ExtConfigDscFile
+            return 2
 
         OutFile = ''
         if argc > 4:
-            if sys.argv[4][0] == '-':
+            if sys.argv[6][0] == '-':
                 Start = 4
             else:
                 OutFile = sys.argv[4]
                 Start = 5
+            GenCfgOpt.ParseBuildMode(sys.argv[3])
             if GenCfgOpt.ParseMacros(sys.argv[Start:]) != 0:
                 print "ERROR: Macro parsing failed !"
                 return 3
 
         FvDir = sys.argv[3]
-        if not os.path.isdir(FvDir):
-            print "ERROR: FV folder '%s' is invalid !" % FvDir
-            return 4
+        if not os.path.exists(FvDir):
+            os.makedirs(FvDir)
 
-        if GenCfgOpt.ParseDscFile(DscFile, FvDir) != 0:
+        if GenCfgOpt.ParseDscFile(DscFile, FvDir, ConfigDscFile, 
ExtConfigDscFile) != 0:
             print "ERROR: %s !" % GenCfgOpt.Error
             return 5
 
-        if GenCfgOpt.UpdateVpdSizeField() != 0:
-            print "ERROR: %s !" % GenCfgOpt.Error
-            return 6
-
         if GenCfgOpt.UpdateSubRegionDefaultValue() != 0:
             print "ERROR: %s !" % GenCfgOpt.Error
             return 7
 
         if sys.argv[1] == "UPDTXT":
-            Ret = GenCfgOpt.CreateUpdTxtFile(OutFile)
+            Ret = GenCfgOpt.CreateSplitUpdTxt(OutFile)
             if Ret != 0:
                 # No change is detected
                 if Ret == 256:
                     print "INFO: %s !" % (GenCfgOpt.Error)
                 else :
                     print "ERROR: %s !" % (GenCfgOpt.Error)
-                return Ret
+            return Ret
         elif sys.argv[1] == "HEADER":
-            Ret = GenCfgOpt.CreateHeaderFile(OutFile, True)
-            if Ret != 0:
-                # No change is detected
-                if Ret == 256:
-                    print "INFO: %s !" % (GenCfgOpt.Error)
-                else :
-                    print "ERROR: %s !" % (GenCfgOpt.Error)
-                return Ret
-            if GenCfgOpt.CreateHeaderFile(OutFile, False) != 0:
+            if GenCfgOpt.CreateHeaderFile(OutFile) != 0:
                 print "ERROR: %s !" % GenCfgOpt.Error
                 return 8
         elif sys.argv[1] == "GENBSF":
diff --git a/IntelFspPkg/Tools/PatchFv.py b/IntelFspPkg/Tools/PatchFv.py
index b6dab55..fc2ee19 100644
--- a/IntelFspPkg/Tools/PatchFv.py
+++ b/IntelFspPkg/Tools/PatchFv.py
@@ -1,6 +1,6 @@
 ## @ PatchFv.py
 #
-# Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2014 - 2016, 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 that accompanies this 
distribution.
 # The full text of the license may be found at
@@ -109,6 +109,7 @@ class Symbols:
         self.fdBase            = 0xFFFFFFFF
         self.fdSize            = 0
         self.index             = 0
+        self.fvList            = []
         self.parenthesisOpenSet   =  '([{<'
         self.parenthesisCloseSet  =  ')]}>'
 
@@ -128,6 +129,24 @@ class Symbols:
     def getFdSize (self):
         return self.fdSize
 
+    def parseFvInfFile (self, infFile):
+        fvInfo = {}
+        fvFile            = infFile[0:-4] + ".Fv"
+        fvInfo['Name']    = os.path.splitext(os.path.basename(infFile))[0]
+        fvInfo['Offset']  = self.getFvOffsetInFd(fvFile)
+        fvInfo['Size']    = readDataFromFile (fvFile, 0x20, 4)
+        fdIn        = open(infFile, "r")
+        rptLines    = fdIn.readlines() 
+        fdIn.close()       
+        fvInfo['Base'] = 0
+        for rptLine in rptLines:
+            match = re.match("^EFI_BASE_ADDRESS\s*=\s*(0x[a-fA-F0-9]+)", 
rptLine)
+            if match:
+                fvInfo['Base'] = int(match.group(1), 16)
+                break
+        self.fvList.append(dict(fvInfo))
+        return 0
+
     #
     #  Create dictionaries
     #
@@ -196,6 +215,7 @@ class Symbols:
         # Collect information from FV MAP file and FV TXT file then
         # put them into dictionaries
         #
+        self.fvList = []
         self.dictSymbolAddress = {}
         self.dictFfsOffset     = {}
         for file in fvList:
@@ -209,6 +229,8 @@ class Symbols:
             if not os.path.exists(mapFile):
                 raise Exception("Cannot open MAP file '%s'!" % mapFile)
 
+            infFile  = fvFile[0:-3] + ".inf"
+            self.parseFvInfFile(infFile)
             self.parseFvMapFile(mapFile)
 
             #
@@ -221,6 +243,8 @@ class Symbols:
 
             self.parseFvTxtFile(fvTxtFile)
 
+        for fv in self.fvList:
+            self.dictVariable['_BASE_%s_' % fv['Name']] = fv['Base']
         #
         # Search all MAP files in FFS directory if it exists then parse MOD 
MAP file
         #
@@ -291,6 +315,7 @@ class Symbols:
     #  retval      0           Parsed FV TXT file successfully
     #
     def parseFvTxtFile(self, fvTxtFile):
+        fvName   = os.path.basename(fvTxtFile)[0:-7].upper()
         #
         # Get information from .Fv.txt in order to create a dictionary
         # For example,
@@ -302,7 +327,10 @@ class Symbols:
         while (rptLine != "" ):
             match = re.match("(0x[a-fA-F0-9]+)\s([0-9a-fA-F\-]+)", rptLine)
             if match is not None:
-                self.dictFfsOffset[match.group(2)] = "0x%08X" % 
(int(match.group(1), 16) + fvOffset)
+                if match.group(2) in self.dictFfsOffset:
+                    self.dictFfsOffset[fvName + ':' + match.group(2)] = 
"0x%08X" % (int(match.group(1), 16) + fvOffset)
+                else:
+                    self.dictFfsOffset[match.group(2)] = "0x%08X" % 
(int(match.group(1), 16) + fvOffset)
             rptLine  = fdIn.readline()
         fdIn.close()
         return 0
@@ -327,12 +355,14 @@ class Symbols:
         fdIn     = open(mapFile, "r")
         rptLine  = fdIn.readline()
         modName  = ""
+        foundModHdr = False
         while (rptLine != "" ):
             if rptLine[0] != ' ':
                 #DxeIpl (Fixed Flash Address, BaseAddress=0x00fffb4310, 
EntryPoint=0x00fffb4958)
                 #(GUID=86D70125-BAA3-4296-A62F-602BEBBB9081 
.textbaseaddress=0x00fffb4398 .databaseaddress=0x00fffb4178)
                 match = 
re.match("([_a-zA-Z0-9\-]+)\s\(.+BaseAddress=(0x[0-9a-fA-F]+),\s+EntryPoint=(0x[0-9a-fA-F]+)\)",
 rptLine)
                 if match is not None:
+                    foundModHdr = True
                     modName = match.group(1)
                     if len(modName) == 36:
                        modName = self.dictGuidNameXref[modName.upper()]
@@ -340,13 +370,17 @@ class Symbols:
                     self.dictModBase['%s:ENTRY' % modName] = int 
(match.group(3), 16)
                 match = 
re.match("\(GUID=([A-Z0-9\-]+)\s+\.textbaseaddress=(0x[0-9a-fA-F]+)\s+\.databaseaddress=(0x[0-9a-fA-F]+)\)",
 rptLine)
                 if match is not None:
-                    modName = match.group(1)
-                    if len(modName) == 36:
-                       modName = self.dictGuidNameXref[modName.upper()]
-                       self.dictModBase['%s:TEXT' % modName] = int 
(match.group(2), 16)
-                       self.dictModBase['%s:DATA' % modName] = int 
(match.group(3), 16)
+                    if foundModHdr:
+                        foundModHdr = False
+                    else:
+                        modName = match.group(1)
+                        if len(modName) == 36:
+                            modName = self.dictGuidNameXref[modName.upper()]
+                    self.dictModBase['%s:TEXT' % modName] = int 
(match.group(2), 16)
+                    self.dictModBase['%s:DATA' % modName] = int 
(match.group(3), 16)
             else:
                 #   0x00fff8016c    __ModuleEntryPoint
+                foundModHdr = False
                 match = re.match("^\s+(0x[a-z0-9]+)\s+([_a-zA-Z0-9]+)", 
rptLine)
                 if match is not None:
                     self.dictSymbolAddress["%s:%s"%(modName, match.group(2))] 
= match.group(1)
@@ -509,10 +543,11 @@ class Symbols:
 
         if ':' in var:
             partList = var.split(':')
-            if len(partList) != 2:
+            lenList  = len(partList)
+            if lenList != 2 and lenList != 3:
                 raise Exception("Unrecognized expression %s" % var)
-            modName = partList[0]
-            modOff  = partList[1]
+            modName = partList[lenList-2]
+            modOff  = partList[lenList-1]
             if ('-' not in  modName) and (modOff[0] in '0123456789'):
                 # MOD: OFFSET
                 var = self.getModGuid(modName) + ":" + modOff
@@ -594,31 +629,21 @@ class Symbols:
     #  retval      value
     #
     def parseAndOr(self):
-        values = [self.parseMul()]
+        value  = self.parseMul()
         op     = None
-        value  = 0xFFFFFFFF
         while True:
             self.skipSpace()
             char = self.getCurr()
             if char == '&':
                 self.moveNext()
-                values.append(self.parseMul())
-                op = char
+                value &= self.parseMul()
             elif char == '|':
                 div_index = self.index
                 self.moveNext()
-                values.append(self.parseMul())
-                value = 0
-                op = char
+                value |= self.parseMul()
             else:
                 break
 
-        for each in values:
-            if op == '|':
-                value |= each
-            else:
-                value &= each
-
         return value
 
     #
@@ -706,11 +731,7 @@ class Symbols:
     #  retval      value
     #
     def getContent(self, value):
-        if (value >= self.fdBase) and (value < self.fdBase + self.fdSize):
-            value = value - self.fdBase
-        if value >= self.fdSize:
-            raise Exception("Invalid file offset 0x%08x !" % value)
-        return readDataFromFile (self.fdFile, value, 4)
+        return readDataFromFile (self.fdFile, self.toOffset(value), 4)
 
     #
     #  Change value to address
@@ -732,9 +753,18 @@ class Symbols:
     #  retval      value
     #
     def toOffset(self, value):
-        if value > self.fdBase:
-            value = value - self.fdBase
-        return value
+        offset = None
+        for fvInfo in self.fvList:
+            if (value >= fvInfo['Base']) and (value < fvInfo['Base'] + 
fvInfo['Size']):
+                offset = value - fvInfo['Base'] + fvInfo['Offset']
+        if not offset:
+            if (value >= self.fdBase) and (value < self.fdBase + self.fdSize):
+                offset = value - self.fdBase
+            else:
+                offset = value
+        if offset >= self.fdSize:
+            raise Exception("Invalid file offset 0x%08x !" % value)
+        return offset
 
     #
     #  Get GUID offset
@@ -746,8 +776,15 @@ class Symbols:
     def getGuidOff(self, value):
         # GUID:Offset
         symbolName = value.split(':')
-        if len(symbolName) == 2 and self.dictFfsOffset.has_key(symbolName[0]):
-            value = (int(self.dictFfsOffset[symbolName[0]], 16) + 
int(symbolName[1], 16)) & 0xFFFFFFFF
+        if len(symbolName) == 3:
+            fvName  = symbolName[0].upper()
+            keyName = '%s:%s' % (fvName, symbolName[1])
+            offStr  = symbolName[2]
+        elif len(symbolName) == 2:
+            keyName = symbolName[0]
+            offStr  = symbolName[1]
+        if keyName in self.dictFfsOffset:
+            value = (int(self.dictFfsOffset[keyName], 16) + int(offStr, 16)) & 
0xFFFFFFFF
         else:
             raise Exception("Unknown GUID %s !" % value)
         return value
@@ -783,8 +820,7 @@ class Symbols:
         if isOffset:
             if self.synUsed:
                 # Consider it as an address first
-                if (value >= self.fdBase) and (value < self.fdBase + 
self.fdSize):
-                    value = value - self.fdBase
+                value = self.toOffset(value)
             if value & 0x80000000:
                 # Consider it as a negative offset next
                 offset = (~value & 0xFFFFFFFF) + 1
diff --git a/IntelFspPkg/Tools/UserManuals/GenCfgOptUserManual.docx 
b/IntelFspPkg/Tools/UserManuals/GenCfgOptUserManual.docx
index 
1cbc459eba96d17de31188f409bea2a40be2f2a2..c8766d5775158a3a6d17d9a0ffda598c8ea516ca
 100644
GIT binary patch
delta 20831
zcmaHSV~{2=v+mfoZF9%k@$A^PZO^=8+qP}nwr$(qv)`$E>()I#&Yx6LoqGC7SJIvC
zRL**U>$ZXGe4qihGv$QytUy58Gr&N|KtMolc8<o3#&$+7HYT>t4DL48S3aM%n-VFn
ze+lbu`(A(|ZwN-`hf}PlMR*z*!rf4L?6<mEvEXo;MAow;3Q~#=+#5ijc&-FG`(A-R
zSNX^Ir3A)bd0g@<q(s9zxG=O9)7DJmUASCsPM6Ae|1JVf_xs+Dg5wFJbn($*VIX5T
zE+F^-&aW4Hp_wz0i=dPd+X}PzV5GOp{e_tLUrOJEKeM-lmfd+g*q()JLYReRFHAQ*
z+-<Rk4%f$%WnQ=N+h^uyZi7THANL9zSUqqbKE0RS-cSQOlZyH3`n}PEd6%NdBUT-S
za<<My9k_s*7mTQG<dF-={kiDELZU7&F6Y76#CzB$epjQvD}-<Nq#q2*#vJ{Xfs&jR
z;n3X@6e77xZ$U$d@1mTIFq3UxlPP{cxc4S!@JyllXxpEM=Pat%@PE2el|I<)kaI&o
z-**Pv+<94b8;<C_=3urVt%sWi({Jed&hBGFKoJ0t8@uN<8GIP9j~Jw`K^+n&aV9Vy
zX^s@atAym+RS-DnZFylXcb_g;(j()}BR`(qI#K)-KF9_P%#FW;6>>V7%*zo>C0+-+
zd0r5*3|d_sIADIiy82=Bp~d14j0JM14cp9l73CV8=0lh+cKW)=Q#H**RzEg^zLy<8
zZ;u0ra%?>0Vx^WHOE>hhqjy8AY7y@b`vzBYxBe}eBj=BHrTbmO&u1!DSnr^2)Me_;
zTwy7*)u6Da(Y*IgAUYk__~W5ee!0v7;WN{q|LSN*MR9<OYi+keBfyP4CUzuthEd>e
zsFTwz*Wu_JKNgn)$J1y%>TYMf(`j_qTr{A2?0w&7GF)I(c9(FE(O#r$k823xo`~1^
z1{jW!EdwwlzISwWIM+$4>M}+k{pphZNEDWhsEY@h62B<qHq&}a$h~VZH%KrcLyCkh
z3$tt(Y$KyBo*L-?{>wiDIzp4pwNo(0;Y?KbZJei!=bH)35J$H2nQ>+~_>n+6NgdF&
z`0%#DEO)xO5_;lh%_Xk6s?p*QY5u(LfEGn6py?@#*9_JoAwQFQMrVmkRsZL0>w1)c
znATubcsjswjY$YGTOUpQNpk7AKOm!@?8%=xbq92Q-^U1Tn*Tb0uZ*!l!FIiOe)kT&
zuotX#T|x;ahzjcCIu41#7tiRjupYpH<sG)obh0QTF9`}me-wTyeML+xYV)U`uBy^J
z)^pYlzDQ7G436&bB$h+A#D#BlJH9I)-6fpWM01kiTA>7-Z*`h0_bpKORA~~CmEI`z
z<#;w-^+}uK<iyFFJ=`r*{{rCf^Hp%%<uso671@HX;S40xB#6R{?#yT>=>brBis<gr
z(VUf3v)XOKt$umd-Fc~DKltSK)QONSx{qfgzin@L?(Xs_`870b&Ktgab$spkgD;8z
zy*s_QUN2AlqI$Wy45rBWbooNwCFe!mky@Z-uNXf_IjZQ~+MHR|`zU4wBd0YHhi-rv
zIbGouyBZr$_2UZfRQ2N0E)U@35w~_<Nm|ibYvRsMlxm(j0R7!G+g1~~<zwxlE9W!L
zn_&cLb<kc+6hX*kD|J?c8};$C4d#FbLkDJr(ZCKaeUL~2`(C8XNt+#h2O&z!b_WE4
z0`ufp?7hHi^^kgv>ayjrYZVxM(w%NlWKE3j6vx${QP}QhsazS1N&xtlf_~8+n(4+R
zR!8^DS<H><fcp>+V+~gDK6|SN75B0WhyuFGg|nZ=Z&ap9io|PG95K#kB^n}o@SM3W
z#GuaHd_Fj?t0^2uvVi*8Wio>qP%vkBSQ|Kbsj+DiFx(}X7!J@ri7A6>aaR=&+XbHV
zg3DQ4%VDRGXe>@68U{d!O5Z{4iwm&z%ErPOo`lJ`BKLPbvk~b<8QR@};C_tX0zaMp
zjKLFTmxuv4gqQ^V>OCH_Q6Zb&pBP?#7@S96eOK}2WAhISE9+v%h$CGPw&MkI<XgZC
z^x~sbV6ZgRih!3U=D=bT;!gNsvr~0w5rn^=OAj5<uva*<!vKg@ux#oHP>rk&HFEd;
zgfW3g<$Np=Q!VrGe5Z+opf^TfXC#zoJh4#7+^t7jrQi9+_)bhajRfiJCv#V5nUtkY
z>m>9tVC7Jx!GGa45w{`)wFf29P$Qn>!h&+ckiDYJec#^&*027xy;L9wM`zzL>`<FR
zFMDv?qeou)fGQpk#=Gb)AZag#&qB$Uz<#1UHf+h$_(LB8#5n7LkmD(t7#wW6#R%{7
z-#Y<j2PPRO3*ktv;YGwr?d=I95^dDNqb@ya8<#7?%`nTd<rYflPbLEN$k5V<54-0f
z1e2Barwvz9#p-m)K_p0CB!34y?hd`AJoP(cec9u%0M0~y%#fpT08CP{*d;hJVgL61
zRHy-PI-~*Ec0yhgP~z8cvx5~D0_hD|7Zxk=o@s>ZG6>?s7YX^_M4zNN6XKp&e?W-u
z+da#svjo3=S}~gm#2HxjeDPjme6e1mvVnOTizucbD5i6+|9nOoLk_W7P@nzO%7gW#
zl88&W0#IsnA21DM?vRip$?rp_!fJK_Nw~9Mtk-<AclTR2e8Mr}c@T=k;lMH@-bFyz
zNxYx&5TQ-RnrPh)r!l1V-EaMmVkpgUDNV5Ei?5KN16Z02WFT7Tg*<ba+87&sE4SNn
z+6+vRr*8N}Ktykovwt}jZ#KKWPkvSbSpMCw06%#`s?2j1rP0Xwil2YtS&z0?qE&`^
z6Sp6zaPA>37&z1~<Tf<&t$-`&@SrMCw>I4NdoVo(g0wv=U*$zpaxN!t9{sLU*S<&p
zyVev@H{o`#T4BAT=Dc@3Vju!t{H$!{cx75Ach6j%oVNf>2K5kJ-TbFtm$-I;d!#r3
z^$hv_w*H-q#1R1gUL%PQoBgof;)p3z8XPsXM$07RRkFg}30?w$mhg1pp7>9y^xwg*
z1n>n%^Le+oaQ?dvZA3Zrq0Wb7PLWGC0fj_u4my1KdXqy2P!lz{B^{vh8?FY;c#CO%
z7%JohVB;f1PAY0~`;&beq)~}j)?IkOcc<5*iM2yj4Dz<p2{CRV&)rts-V!_naLT^y
zf!_~Vg{R9L^*rE-Bh2cI*xo<1)%NuepG8%i58`hTczF&VnZv#hFmJs#U%e7&78DRn
zAmreb$Zqqh5-;|YP^=wCMju34_4%9HR9p2-oOg0~PD#8g&Swj2mTaT5<BT~V<Qk;a
zDaRh!b)9-$wIq05{VB1wuxDJmsTT1sKFC)H?~5McNo8e+T<kUO1hLoeJjN+3qlbnW
zB*I?;-@`729tqO-K-sD>TE#SyGKNL4(P}q!e!m8j$>Qs?r>|{Vl@`|X(r~D8a8o1|
zbraY$V}V)dsYJ0P<Peh(%#fS`!KFF4DhqK^2z-6_1GBJwVFBgf>}ei>`kz$>C-xv-
zIGi<8vnT#YC(RIiwyJZ5S~np+ektNRbyOjQ)uZ$<H*o&9b}|-sZ1!5|<n(@-lXPOH
zj^tzFDd@nAX+vYz#JFA-Nc9S8s{1EX>9;zuggFgUI(Y*E2nW0UoL}dFlZ%UMxmrM*
z`S+pDS0`yiJyfsBEaHAO)Ly}<FH~;mpA_9P<vX|R5KisTBnRn>b2NJ;xu(@ualZs0
z{ecWWx&s9q(O^AL30{wlwONlF+fn%2HRN3laia#HhiK(kxfm_{8_ed$r(f?iDEjtk
z6Ej?#?Mm6m*dE~HdVz@md-~A17o9>6pXWuBL!C_f7j(Xl`ui8i7ff#oh}_Vq489G@
zlCnUZSAoiX{O{*lx~<j`E<C)&8{eQJzf0tM_1r(|4`t-}Y7r|PppF}gS6~bxH`KSx
zFJs0MOgOv)m7f6|@=$6|!bf+0v!R?aJCvpa&IF$RIT5}MS2`bnUpBwE2fXEXp!jiW
zUw676XX>wFuadN+jJfJZsgL`LXu~Z<h%~o?AX}PNuc@?ZT4HC51Ii6bR~nFbQWw}y
z?*nlq1d&r%4=C=1^K!Y+zhcV`(U?HxW9?heW~Axi;LE`gCdz&&59+H&WDZL&UoImn
z|AZI_5HnQsUA5l>q@zshJ*TLtA_gTneif#^)RxX91}CI?uq>M>yo9%OTM*!6Ld?z;
zEA!fh>05N8M(>-80R;}6?~mc*ZJS+qcYwg7Cf8h7WsJ(k_xr&G&{q$o35d6UEL={s
zv97^O5d!JFrp@ce)C8Jk$S6|!A?l{p&SEEr<l{SzB--Nv<fk&yNI_iFgy;^Cez#t5
z=f<)Ao^e%NLT=FytVendB-}>*^K<55M1UE%0*(4FV2ktx5^IlXvm<+fQP#M%!3Q<g
zc)!~y?$dU~W)UD(gRa#tXy=vy%)1e`v=H-2%rC=GW&ES~)H%S4;GLpx9DIF9g@~$+
zU_k2k5Ml2C^>4Gsl_0wgUSr~QM@dF!1C{v@A}`3fO<}QX(EbgdVTi*4ETZ1deL7YM
zQsY2qr|Cc3tNQNx0qTKO+x5}^Tv4DX4d(4`4bYl#V+&2jSxC1PRpLOPWx?(<DZd>5
zA=(YSdQ$&gF6+_iqpegDfZ=YJxUcpK!N-<qxA+b)6B0vrqwOx9DqIo0eUl`oDVgP+
zAKkruhp?KuY9v_|i}oV@-twmrioZO0+~vj_Y52VUL9SKll}1X;=OIv%Z1Jj1DvJ|c
zE$i<_njFNZL$k9g&5V=Z11fdIZJ?G<QUaVXPsx_S$%Z}xa&E4qBuWGIdXy}KbT#(A
zF0mQ_|2jLpo6zD03PU!rP#!ICJ&#FAz%y2vGnTIKuQnJz*%6`*cYK3)HgF|VIbiYU
z@U!wVlP+-W8>680iCB@T^LsS&<=N!$TJBU$jl-_CjBHSj(6$C(zVqdbz>%2VQJS8-
z0YlZ9CCCR$v&nJ(n3QLKGBpL1XyeDVwAcf%o;UU<F=lx1?*Ap_U66xE9yFmXZ%dST
z$RGrYjVe;IumAf7#ov@J5#@cJ552m<-8NcB3C_<ne~X`sAIV;GOqb(g0MB#VD~l*R
z#B%1EH%;x&Fa*jD=b$hddLFEUm}o-bVa(`QZD66d4`JZ1B?=!n%TZTN;?cl0dr&OE
z`m^%^#D&DOFWb*KYC`Smy+#H8Mrq9fxq~L1@B`;Q3$pI79wo>01b*Xz7Pvj^GI$=j
z1=i}?WiEaJF3dIi!n#Fcs*|4m^3KL9Lx{9T&dOga9Cn(kc~_#D!r$xZWgD6JaiLSf
z6T@h!wTpuc%pSD(hfTQmi1oG}DGPppoG6>CZ+Vi(Hg`ww30B|cprgg#;d~HXKr~*z
z9h)7ts42mf8aqnY{QC5DeHDsq7nxd?bbO#xNLRG5CiyGTG(~;aT>ATW$~#5fKa~pg
ztqr4=Hx?_gvsxN5EISoz?pR9x)QreV3-kfYT%_3hO0f7_{mtomPm%D;{<ho#h^HHC
z6Ux~_a_;AqC5uD2?aj5!&MLnvjn)HvnGeK4`{&Nm{y3JIIM5jqj4rM~4!dPPBVpKV
ziN3N~JcmQZrS$-VR)VD;ziqt+4Rl45%ucU4$gkDQ%d1^as+2yufyz6@6Ebs<%vh9(
zW^E*xwVq3-zzs8dHe-!L58JB)Fe{c(9mZTn4RrpFKuqZ9EzwaQyMkgOPae}W1z>eB
z=t)#OE?JCOqHJXypp>yV5eaa^y5X58<qP>K)6}$Mi4XiLYD9~zJU$rrw`7YHXS)z{
z#%M5mV?k}+@fAZqR#~%9DI=V65S<`rB`9&dkAI}Rlc#~}*YgRQ=0#8kB!Fq`F#MGV
zrBpTGORV(F!3w(MO{ZKORhl0YI2Ma}UB{1sB*-mF2pv)#^eSad{!KoqKWY%~spG`I
zF@YfV!`1FsG)XZ?wxCSQkjECgqRHRB{-ek_gU6A&49ubP3}Ux=1*hszUB7>&bn4rL
zW~ItQR<KxX$$CydWxBxz7;fPrSXFHHK%g>N)4@C}LV=}F`FyyM;}wWwt-f`sA8BVz
zi@4~We?1C!i{vC(l6C*|I4R`!Irx>XzCkCToj6U$xGD!cx=1G2g02_DAJn1bIoZ(@
z_R{&-qT6f)Yp9d^z+O6GS-NJfZdG_z+lU?^KGe`K=^6gM;hr@PNT@RVBZvHaRRr7M
z<d9_`G3-jUF;qk<!WnKyz3dXsmHd&2_3EH-jIy+m@2TsY<t^Q#dJ!hOWKNPMT5g<r
zmKE{Y5C;1MNtJU2%CdGuJ5q+Tu70i?dgjWZf9MNY6;^MfnJy72wY!eyks>1xl|+U%
z9-OC-rTba159!wike`+YzpW7##pG&si={tW0_eBj%ez|<+TuilHcPK&Uo5u=t3bFM
zP_Ii-T-5%(1u%Zhws%7Fdy=YlpF9tlHOEK%{oI}D<q4kUtXACXMH}A5Irny1>5#!n
zDq%v31mrNSaauvhuc9+X+9TvGBSDj1SQjo*wP<xEoYph~)J^lP#qN%vXkft*uWUet
zu6}dNTpd9vPDbLBH;Z9PY}VmjeH=f)_4V{t*i<?}iLysuVj#P=WBizR%Yh47Xc(BU
zIcMyXuNGRT{(MAiK3f+(G^US5xhu4|%?RysJJ#4kR(HGSoQN%qUwO{|x~#2jn|{Pd
zb`*OLFHaZ%0NLBvL?K;QjVzI^7?RP7qL2|=ZSs$%U!6gm$;L@$4JWw2f4|P4(<;+i
zL)u(EHqPAk0@4?gzwI47oI28E?l|zWL>Ye=O5>Ou+S3+YZXD7*B%o6N^kQf;Tsvq`
z$X+$nwBR+aym-@>a!h>3df_(JItsbYR4sk+z=>}IX78odI&d@6b-r`KJKv29AqI9z
z>g@tql^V_?N9<ieha0fCdcVE|xOCFXA21v{X10|*uAR+TI@f#Qk%#owsN|FjM{p*J
zEU+zfy@u&AS98m&vMyaWG5*SH4{g5Un`#X0YM?6@|IW2(?R%t#%<v_`%<@%_uq?%N
z=Cw-&{0TnNlsq9<v80TcO08Gzy@0n=I?!(HdK2zxWa<sfa(Tq-mvk5<pZCf^y`xgn
zvjhryRwWcL{jirZdZaLLP8Kns*3bj~6@ggancBQsP4Zo&%+J?KQGZTv&6E78gh5tc
z?SM&T(h|P8E0Qne5tRKf*Mv^pBm*RGr&e_cII(!#_VAOrsVi`VOX`;Pus!(2IB_NN
z!o#2<WT0^5T*>h}-AH1WWxCW+m6z|(3`Gg=3zOM)$Vdgu;SO7r#NJL%<n&7;2QPw`
ztTf@%IX!a9th7`aNB`xFRX^0TrvK=Mz(pt2Hfo?d$u$)XT3>~F?;zEMM`5cuHln-@
zASR!cCG`RJ7IkF-x^@h4lg-7y$0_SY5i4<_h7+E>wc3hWDpgV%*bF*!6;cAufdd@|
z3pbh3l<E4K=(#DMb&DJA+y{-AK;=eut`fiYaT#@wPD_~$!+1f%$|*{6`Xg58V0|a(
zC1^*pOE%{5b`3o#yUy-NZOu~s8~s)fV1sY9vva?Ek`3~obYlX%(Gk>X!3vDy%hIYM
zSNywDGU}tmG}vFqh!5a9@Ax*20GKcHtGqDwr*9gKnwCFG+i8&Z*DHnD=^Ff?V(+(&
zDvr!UOy{nkXP-XJbJVOcuIajbeDXElYBNMD?k#_kKl|PU!z_P_g0@suEmQ<lP4HY^
z_7*-e&-*a-e{ZzKhB{x*;qJ|lY8!F8Dlie6*_5=t3YMzso}|8}2~Ve2=ErJHbLqG#
z$myKZ!`2%F7wEXCmQCfWNNEY;^(8l_yZ1vlFkiqx8gdbM2O_V~6f5)7y4Vw6;K?u6
zQ%~I@j@+!RM@Ez<P@-fihY|x)lFJ)4*eyyb*PERlD$Qs<hHNYq6k$J)!Ylb!HV}*~
zaQe|Ef?qsTup%0ra{Vnlq3O``s5^#aZ!-A|9Q2&5zB9D4FC31W=$#-NGN%44Z!Lr(
zjTGO@BTsn38Vv@pqVi~-slc|cm#5%Ra_RG_P=yru(&q}b5)q~^2C)L5e;A?z*q;Mw
ziJxli4aPbXQfZ>{YrR_gmJFAzN0ryu@uiEZ9Qdmo1az)!!9kyiF~+{G#!B|kQ#)^Q
zYc~lOfa|b%E%GF!N{Ojeb)sT~{wT(@V|Bji(+2H2!^u5f(<jrJuB!c3hiID`eiiHP
zKa5-(Z1(EvV-^k{GT{b<xTPi6I!i)o%4um?)kAmN-Sk{j(q)-iFK02u`k=C|ETtXC
z@Icec>tv%DhVI*5Pkycr<3#i?pqtAg_u_Hi>ZK-7lJkz+^Ox&Tv2RG0OC>|i;!sXM
z2JvDeN2IcbF&dd2ek6~`L;($26su!AQy+SkbxY#c-z&Rprm+ED8E_EMg{oTV+7q-D
z)TOLxl4H<<4b3D?Jti3tD|NS_j+c@Mb1X3NFPRnW$%l2sFY+dGoawK_(fga1paX4Y
zk;hz6eq+ee6E$Xqyva{iIkzQp=2c8t<JlIQkAC-5D0(;{&K}IcpVz3qK{jU;C#l$n
zvbZ*E)K$1d7;*ue-)XkYwb{{qo9Q}=dyXsMR<%-;ivY_Batls7ZTrfB#xTYZ@W^N?
zmKZjs8KS~yi~tvSW}gL5SkmyT#2=MJ5rU<HZWeW;oJwr9uPrHsUKkT5T7e~#3)k(;
z2>uieB9}rn$Z35LLe(>EPsHCED7O1;J6LcMT=U8tb?g9KhuK?d(b|;oB)Y%y(A@WZ
zOs|4G3=?P_$Tw8}BcP$U2j#%QF$$O2NkzhDEWc%bmk39Xfs5nB!?9VSQocdy#Qhy>
z)oO7vSlXFi>CKwy?gH^q4agMhg{_$9zG0g|P(^xmy~+o7ETyXpP&RjTBi3HO7v~#7
zB}c&H8Y=-Lx9Uej+PZl{ri2jm#Yn#&J7lje2hLJ0zAlc@SMv^+2R!-l1R)!rFjNO6
zM2o@zmqsOZ!c!5a?-YZXuxeofzX*?ttJ)(HSRuCe@}>t0(T<OzGwZR4st1~e1J$(M
zi@aFTsk0g<Uq@expJYC+_zpG%opZafT7YaG$L;|%IJ^?Sq7C;h+FV6|mGZ!1<Zk@L
z;?#b>xsh^+IfxM8%jF5Z6P(yPQ3!-nlokJ+WpTFw=$t#pu=-_gG$FHY{B$p>TpIP*
z2Xp)!6?NPlL$>0OS@V}+!|NJ-`A%RcLxB5ze4b|s8FVpSti&Xm*&e3q@{bc0N$>rv
zaJd1OxN7#ULguM);vx>%7`7`My0Y0#I|JFkUnUtN35hL<CNvl)!22&PgETF|zML`m
z$Jriq5{t7Ehn}_{<+f9F=R{cs#;10*8GjA;E1Mi04q*=6t%_6ov=S43<+VzzB6N2#
zLx_9AYZWVtvfHR=dAc4y;zb;s87?8tKnej~jY?!2Eb<;==<*5cmBFk0q8Pt&Z-Sm6
z2zc~V2g^CO_;BL~xHI7F&JUES^6WKXU1a2f)aCFst#Vzp9GE3XW|S0%%W9^eIZuRI
zSWIG&S2oD^oWPPNM><`v`}CotgRVLrer(qh7d(c&c|eI;a1Sq{4G>=WO@>LcrkMb0
znX59jgm~NnEwxsV!G#C@woM6s`Wq42JnzC%(}{<NWUU_Y#1qej=*l_oA!TV`&zaPc
zwEx-vi;GD!uOU>*EO_p?-feDPJC&eY=ChCZD40JxNIJtv)3Lg7146GCi9(cK&lXFh
zJHUyOQm8lJGknxn%cZ<_AHSa^-vF6sqfSn3_-eAU6Oza!F8H=X`)tMOm9d83O0`-k
zhuXN(1H2ZC;}%*IX(sOn^DrM3ItVDzSv+`?B{+%^pAoh!%8Y!b;~8OaBzPBff&8Ga
zD}_a%#>91N4Lk&1wr6#4V8}5y5QUs@5J|-zJ6+=k;ER}56*r!+gF#n$YXGnQuN`(w
zQ<yo|ZQ6k@eQB%rheF(so9jL&80;%yK4c|PmhNEUboVBZ?&VsRtm%32tu<{^<eh}<
zCNS8`ydrEm+B4BSfUR9Ocbn)oN5{AGlF<~cMZKoskmWK{O*SsQ^KpWYo=x)XOa`4)
z{Uudbmko`|VivIBHYn%20l><2z+QFFY1y?{yPV7u{PgdL@bOmePD4?U%9xg6*)Iat
zO0e(A344r`Alstd5roi4{zXAHdW2oNT_2y8s!)R$X!oi)7m~D<+!B14q%E@-`hMA{
z{VGqz@(0eEabh*#53z`zD&A6d+Mz1m8vLgyB%3=uV7Z}ua@})hG{ByreT{G=o~Wy+
zJ0AbUMM=^rRCU$@-m|f!hG-aiJW6_hlKR&e`=iC|qkV~^VntSKwW14o7BYH_I+_k{
zs`_x_%<q;o94oZYw)e%)Q*-BwNM&@nZW9+SL9qA)nXoFD(7lAB;J&&n5s5!9-sbVd
z=wHu=W4KSyyM%X9%m5$L3JS>YxW%cSgZ0v@%X2d-`d`1PVUiw;3;K!3;6WQtGn%}7
zy}6hVBVO3fttBaZc7-L`8fxklbrBBb`bF?8yp0jhO%bFPuJ<9FBtOSwpyLc!=qJS9
zDVBuKV&vz5>`2>JZ|8eab*%z%93qIWuCH%uts3n4Bse{+6#)a$9X++Vzx|nd?V<|S
zOEFZxicIk&GIGPo9&~u#$;1UUqLn0y>D@RT&$=xB-p{?a+_lSd(s|!F_e}1kSu{tM
zf?K(ucL$G?-G@P0j$^q~j7ISn&=5YSu%8;Lu_$d5dFT^Pe)2xlUAW-my&ELECYgQg
z>E@B$#D3`J#Q|m*x`m#T!K6O0StH{cOQI>G+|as7Veu#-;`2}8&iIj2#ix}YgDnYT
z^&glngR1g2_l9lmGz8ej;7!6f%E{xb#B<wdQlC=DuUo(tcs%-|iHgB6PtXqPS#y;=
zXo+W^S%LR?!wQE)H8MwLA^@1uZIW+kGJ3RV+~I*5_W*KXaYfCd7?IePvRZ1=3g`M2
zZPW7uD=mG9no@UlMP_cqvCdT@wehnl#McH^2Ud|5HXa@x>eLO>t||AjJI?Old(L}v
z4}w%;smCQ-0-iX#H4jcs-R&cqUtkLifyg?4Pnc%O8KqhJ>8*<(d=k>JNeJo^NMEo6
z%&Kv)W&!qmFW0|7WS~y)xLZ+uId-9VVqn<bVAXu|-L~fo2P-ZkoRXAPLBd#^1sc4*
z(3Ibf#QDiDiDckB47$W&6vLaC5o>JT9)&9paSm?VR}z}2_GmZJoRrr-GG8`daj+eP
zg#<$eLw}|dM#lIL7%fdl5;bJ?k(+YJP=*422?Ej}S?lHRV!iB`PN2ikgzvSrkIaj(
zH3b`E;FEn|&0L0c9<ESPsDCMIW6~5s$aWc}Kow|7E=B4}ycJUwv$Mjb8f(XyY|^RW
z9$S1P**b=Yddz9|j)RO_ASq<z^g_(ZH&Y&fG&5c!7d!M^y(9lQ_1<htI^y#a9Mey9
zjR8zfPlQiXENi9pq-3|4m685&Eafk-OuV4CW;mFC=rDq*zozf=A5W2Pwn|-NO}oGe
zm-jF#q292>K&T`MKC1TsMN~q5o@`Vkd#&mk$EQ<`qyC*-LP*#AgpFRcivHMKy!M&-
zujCtTEwMm;?qMv(6m0uvL?mCaI*UyFc@>}?olV_mw69%nLh%dY0v!S|{xPhJHZ5x#
znjs6XXD<Y@+bI&Ivfqpw30xS>jiA3Rx|^q{xPPzhm46bC*1JN_hl~NKDWe*w!uVIw
z-1(&{J7~8FEt2Fi+z}iXEE4N@@P!Nvg?PY5>hJ4<Wq#*~=8?>k;e4eE9S#OfY&O6j
zA2W=rbdWCab!xB5c!XUR3M0xr=SpUPdxgURxoAs(BTwyF#Zd%YgJ!>no9`J>dX+kD
z>d|en<}p^U8PWE^z2vj?g{FMg+rR5}>%RaIqFyq@;v<qAeMWCJGc5b3yh;F3+xNXr
z-xhqQy<Y+gu<cS)_aHj&k%;QLp$pLJpMRgtVTFfKmbKgtoIPq=ccSR`+8f+(qA2V1
zK<A~-8ee-1W-jUqC}psoqq~!MoH~}6{`<RBIA!Jfl;@NN9?yqA`98OLi=rGce?qd`
zMCMec+iBi+b3xt&wuj4SLQ5+un>o%drkcfJ+QmT?^%b}NFw4FUx-<&{EEwREKzsf4
z*0#lE=27f`uOX?MT2okx8qW}nPzW?i;_&=u)?;_*nF;j>cIdIgDqFRJQe__hm`EN4
z)rW?0PRJa^B!S=^pF2L3W$&iXpp=^wa<xE74Au!N#7Da+aJOL1$%_sDNP;U6XjEZ+
z{tB*q$Iv7Jn?|*AXW&j6I1pgZIlrAtIFcq(8O>nNgf@5Zd|g7HYWnB4_AW&C)9v*h
zJS+FZ47Y{QZ>mcCw`IILQR)P`tBK^v+&0uEi%9!yz5vVshqLkm)u)AcoAM{e<CxV5
z+;M><tufac+_wYepVrk5+pbThmoDAuw)9}7?tLL!mx^d3t1K-$gE0Ux0X0K3HH<Yh
z7sgdw!}+h(!GKz5PYsYeZmJsgrUagvxa6OY$IvY8fR>u&zIL+qHHdX06FNIa8;{?Y
zIXjty6TcvTeG)hVcY=h@2S-(4pV8A+aAj5Q?{b}IMK@Z$7d5Mx$P)h6Dc)%~pfNEo
z^mW;`)U%2Rg#bc;_;3ScSIPKHz+#Z<QcP$d6|khaNDUyvHZ9OBCUK=wV@l_vNTHEb
z@C~U@Cn|wP=N}}?!j?vptd3tv$Vz3bgVNKPRG=X|8QFzJUSvIrFR*Nn`&D{+i&aI9
zNXI7ZCTx_?l+Q$%FfjX`<Xl%4pKFO%E*6y0!PvqMU;EA}<O>6YvmxB4UKdvk3Fn2b
z^HY`G!{G0(ReA|MSS_FM{CIYGiW4W?t|+AP4<P5VgnL&9xg?fs&ONq)Wnlz)OoI~g
zkOWAe-w^U68cQ-Bht(&ec>K3#Do@_)(wBGLb9dVT@B^eD!A~R7-_qCiJCnQhP~7{_
zRBk$3aFS)EB+-B-)Sl@juMav_A6wZQFTwX#M-L#5d9qEGO}O-Ua)eSbAuJw3K5MX=
zfnkQZ3bJI*08N)f6APSWg%l?N;c}fsfQ?T1c3hR}TRGWasoFkEY*)T$DT|RQ1om1_
zv^#np!;}OTBI|;>&}pz&Jy+P084ZE8*YS}f4+9>01O;HI7lePQG3bV;_@Mkb%0a=(
z;3M5#B<iC)iwKrZC3wj~b@G#$Wxbu73S*=F<8qeJF<rr_-?XS9Pq{VDX7-oFH-IUO
zDU-s8WFCUDY0|X@c+!S-p&M!)9l0S%wf!resAl{?Z#Z5Eu#J$0moOC>CC2BW)ja!*
zF_MrhAp#Kl%$gmVE1#8xskU?s4&g4@85lu}MFYkm4iJRs7oNU8w0u>A98L%$d7~3#
zy8F1V45R@_pvuo8ZA6bFO!>se%V4iu+|QoHA)rQnS+CVVHSgK6h@Hhzf>0t4tAdz8
zIc*ajLNTMSg^&3;d+}wMF2u0_{RJ`=&=C7Fx&=6`;*Ls6%BB^^hMfi}Ol>&igL4!X
zt_6n=MZ_NrecGM3b#f-ql#IkMdVzMJ2FCn4+<}!&qWLh4p3;sowABQ^igq~r_YefV
z4ExYf6s4ANykL<)Q+rdm(-7@bwV2|OyG<-O69LEL2cZqWh7^72>jIXwT(^Q2Bd6(N
zAO+xOjqvlBP<2GNtvsTj)ZeLhYd~eU25qdz7t8q&afB&CD?MTRYnNOVVMfee^=Z*D
z_N(fLpE_8WzU*_}QN0Ts_o#f;dKDD!c9(*m_d1RQDfz=;xSMQ!&V~n8lBQNVp;(Ph
z+`<D~6y}{A@}TO0B+yQlgGf19*={{Zsspfk<*IXY{mfAx82Q8zXkjxL|GWev_}zL^
zKvqlM8pfpmSb0`N&u_M(r7iAE{aHS>IB`Ed-ad8Hj$y#@ou80h+WSLi0@I`_c1Vl+
zU>L2H2gb$TAc$ecAJ-|gHm@q9y$h@Ia7k~Snj}hZZ_K|$Cp+9F@uPire@v>HFb_D5
zS-qBPP!Qy)-OMy(#ZLHIwbHqjYbZx?X->2bnN`8e-bAnXV@{<dFP5|Qwf3p4Aorf=
zCa<?~`jI5jzWT(_4cQRd^Ma3ROh#9Ge(bMMl?jxbDPf(FXju!y%!5EZR8^8k(EPD1
zR&+@XBOgLEpxYPJZ@ff{vMYWvHwU<U3+xZ|Y7JeS&Q9>G@Th3K)`7mmISpODi9BFh
zHn^2KYZZ1Zn`7s$Merr3*7K5_sGy%*)8FRZPJ`67b1V5)6+liiGCR<8sNaV1=PS1o
zw-k9w6bVx`(vpi*-L~+AjZ|>qrovU>*U!F#dr3ywtwx=9`fLu*N}@THlm)y}P=Xj1
zG!MB<IF)9aA&PpQ5qBOw#x4I^Ww~|8z;<&d_Q_UU(Lv+ksI9+-RQ{zyfFOqO)lfo|
zi&X4S<iS5V+L+#zM4uOgx)`NwTxsMx>BUq8VTjN;GL6fsGhLH?o0KiSkbVV;w^Oq5
zScgEM5KCZ&pMW3HRgc@@i2~>u5VyE{&?r}`W}1q*e3$~2rFattW90W}+n>H}Z{?rS
z;JtwCx^A2DO7v57Ps9>$vPMa*M&%Nq$CxQiWv4-%*J|O9Z&WPy7)f9s9J?)F(y_$E
znJzL(M2%mv8O4tC4$~^V2Lz5K=;QB;9#?HuNOYY+qBi0TXjeHyaspu49E}K}p7!_;
zDn^0Af;!BpJXW%Uh>M>T-+{JDn1--($6_=N!q9xf3MgCK8cvZ*Jw>+vQ3t(Xj}W<Q
zFmb=tn}52y*t-J5iq>l{*!sMpV7#j^aSxUy)7W*#1tUBL3O<DJio}0yN4Udg9bBgd
z`>@(rgM&!im#|1h1gy~(?oD&0Q1fGf3q15j40x(xN=y=qxrgSS1=g0TQ|CUAo5xm~
zeKA7;>5MTxPfE;GAZafyobXQUloP0xm<78d4;>y}aD72XL2uqZ={GVNh#5s@uw^(;
zGu24J{;LOLXqHkAzc6Rc4KyL;<L~xlT}%w24{5MYrO)TI0Ngdpj#(4J+jcYR6blh%
zjMpqr{lc!tYJo-Q881S9(xj+M0>kr$*Mmkhp1ONZIu{s{aIRTNBsVHb1tmqv&R8{3
zKG8&s(iHwiKZd><FyUPqx_v?w(Uob_|B8rGLuOkK7{alLfE}|i6@vGPtrtxwkdUXs
zFFn@^;Y^F?0pQtc3kv!#F<HLPpA8t8H#vhmB7lV5kc1rFi!&PDvI>lzQ>-FH{xMgm
zg4{su<#68H@pP6z1rJuQCdikGJ~Ikq_MB}~P}W1-H6L7?W3~o9RU+!puSCJXaJBzI
zZ!K7HedImlH6dw!3y27!JRLSYkAjBnUvfhs(NA;D23&J+$6$*%XqV-vwq5-zgwF;g
zv#TcN>eM(v?|)I%3NV^W&rS#rU660kUg_FtBy68XhBAeQc>PJK<cyoa!(4dN*Zu(p
z2kCm_KT{y)UFr?o9I*8>$EijzP7c1Lhx<BEfUw|!{i)5~HkbhLh)bDFHl664{!VF>
zfF?co093S1@j*s5+c7%9tn^5~D}~5^rzGK_60#<DZ7gV;DtO6NL&~^^dM{ZNU$Lq0
z$z2>!dVM2iTm_xjr1;cfd~LZ9G~3c_<OEKS1i{r9ILVX+=mC6e`g;poGL<E`nkufP
zG~S|RU>fVB?p*IxBlex<%`jSp_NR2UYd$}$0U|WW=SL&*Y%SzGEuUU>Oqq^Mgb-;*
z0Ljv}McBPgEbub7;X|%gf(yJs2Y~~Qps@!<s&46d!ipX|PqzbG)CDIk!VD^9avBze
zCIkX_&K-rGh<Em+9MOCl_ahrmrWXln9Wj2s_Cqj^?PX^h()4Qg$0!GMD+xOT<@D`T
z0B@o7*9iyCje=J;AF{0DhVeOYY$pj&eG;L1Zta8~&gro%E3{#Ka#*Ux5_nI3dNLc8
zZ{@Iwh;)cy3v8J%_Ak@cQ7b{@HUiX-40sG}1EN0)Jfb2JTUVg5Dd(Z6ZJxLABU^fq
z1@^p{uP<1-Ts9=$n{cIB2s_|@n2csX0PleX*9CBsf@q)I2kY;3wXaNPOuSQ%X~$*-
z+oOJP4ZB#Xh7S~%?eo&d76<BZtG(b~$n}&}pm$tQ+gIo7yw9ezITg<S1+8?{@(;tS
z7XiT*h9K_N8!@IC*LeHQXA~cJ4q<i;em1`ZXx*|B64a?=YF<qEXQ%e~7A=&P0b>6$
z_wtpb)ATO0k1(ywNS%cfjn=i#ilAzyL9_H&hQD}&F%PEBZV=ohXbGw+H&`@AC0_f#
zWrIIpSirY@V`|0Ze0;d|qM2(BD(AIU9+#(R5#R~8Ns1aEpbtJ`85p2^FU387rHU#j
zV`I5-giY^h{r(%lwvyZ>!d;{s52$Ko!io^b&O$Ho)IXJT(h-NyPv1<`7CHe2n(spt
zEA?SJ6v!yFqs&osAnr3_%7?3FsG&j#Vf54`9R7Qrt)=aV>0Khil(a$EVbnp|*D2fw
zlT+w*%bL&+f!cJi$bX<-xU&~u8Uaq%%S_ItF$q7{s&AB;$QU^pqv^5o0=S};bt8)x
z;2Uk%X4Q;NKF*j=)rp9RU(%J-hpKiTU9}x`E4_P18@<2pZFszu-Jhc-;3ofaogXM~
z{O?54X}itb0>vLzez3ZYRvRPH47YqtRYy;4=rP1i8v$NKdL7Q}1i-0`AhZVON$~49
zVv_f(r0DIE1Lf*zht~q&7!d#@9lfsWc#tA7sO^VeswmnP^UOsvCiL#V_^E6em56SY
zm6~ihG|j^Km1923!u79Z_;Y}WJRO34l(-;J4m!D+-CmsGBdR@c+GSgt-I98m5Xa@D
zt$vVJfiOhL$!i`}*;e<2apJ2mv%rv9)L2q@v4OwskwNkOlmno_C#ql-S!*$T#43}W
z{o@?r@tISRzId}<HQ%;#^L~G9+y*Bf%$`~j@akhX_lF@Vh{oV4yAJ9EQGUi`mGww>
z%Afz%g8l5ag-BN^cG{o7@N~vY4J`=1vLr=MZAtqiAvdt_&mVqK^vTrSW!VcQ#;vLD
zt#%W;JHv0OIzj*@EphOtK;1aLPA1X#XcBEXGc9+pH=ADibWOgEws_x>+ju-T;;QDb
z)VVt?I1E|bf=-Xc<H0zo-aK}-N6w<DB-AI_T;*&;Ty{wgrHc!4kw`naA&1tKEk>KZ
zfvzX497TG<Hpn0E!>P;4fZZBUW9OyZCfZ?3W=u-#v_inoiQMfbd!y}*;iH}*mRTYf
z$b=<9^j5$j6808=*SRMcL4}hH{DOzi{ZYPCRHiQ<*VkBW8Wh1-abgy~0OeJ#Hqfc{
zGd|ZR^_C==-6JuzICFW>Ii%Qg;@`p2SchZmS%~CdpkAhP8m~dkaMDO%KJH`FAO=Ya
zRjJj=Ap!_|t;9T3%{=JRjKAGf_`c{>D<4SX{iW$=`M7jtGP=1ePE}zpY-M6@oR&H*
zUc8WOloTg7vm~~nw<b9-X~D78h-$v*wUbZ7p<FdV*4h4WzjW(XC=wsw9E!?fF_O|=
zWhJ2bLGBKoetc?LvS>aPtAo*IuhZ6*c3PM!F$FOB!hLssuD!Q>W-HO4O+H>7JZLn}
z?HiSXXX?sRqBo)jSZWJ6GsHpj3Err2BFIzX4U@)XL0EP*VvA5A_SJx2tq;n^uSV}$
z)zjc}ui`MR^Y8e);r`0Kph}e*tzvuN^A+G4zOAyKd%MAxnl!TP$C{0Or?qBT6tD}#
zI@jG^?1j`7$oX+WthyU0>Twc)lD{W<f3!tu6d1PO))!=FEl(0y;-rC|Hl2s<P?pA~
z2Q`lCeLZ9_)u^dcwZ_uppapTjeIi(Ad^2Vdaftr-i}~*t(cizIK=OY;!4d)5IE||e
zlMpa8xE-t&;6OllD2Y|<SO9gc*hMik-`b_WNXPAePWW9#Fy1!;)XQ+*fD_$+)z|T@
ztgY95eGqIi8w_g%MSLXPw|k%3&W=y2<z8Ce>-(s6m^KzMjyW1+cGFIr)M@yB#qEMk
zimqmsFeO`EnZBEM9#?Me0=ztQ-CAyis<ePa7OOA6O+BtYUAr}1J^_W*GOq*8Ex;$;
zkIm=%^MtC+_qnpy(>u%6=aV`b$=`<&$OS2wSgjg4-i<wiTT90~oip37ffF0syQyAY
z@9FGcvuoLGO05FRE$8Bqw05+2{p{QI)}7eZKegsa2M!P(Zwg3=F6@)p)bH^}<Xer8
z!)npF4tDb9-J6>=fdG)@Wi(rxi4$5l^j%;dnP*suXUm3eoIJtognQ@buF9T8@d`eb
zdz<#h5jm3(2&}HM*UQz=5s${oyz&`kI=lSB9!@pJnah<AJ~Zf!_=ICieL<!h-_6V&
zkWMQbmFVyG+A83>$B#W3`0Qp4*(8P1y4MrsXTmAl%}$IU0s!1w)jGH%fNkf>>$0_a
z9aQrmW2e(Hg?5W)m2$3_Ac2#M`T1&Z#(6{b8xbeEoH!!f^ZcAgZLPmCk+JvBQe!v)
zniwN7p%GjgG34XL<iKz9<n5Q(<mvu*oA+TcnfsHaXL9NBwe{Y;{#d-aY5jLT>DSQF
zm6MexN{Pk4#sKRo5#8i#o%8O;+Ds77L$&DY6B2~upj5s2=}<t{<tYmiNxQNK|FI!b
zry~@lMwLPgSq4o~VN(M3#JuJN(4qW{l9)nF9Cws`%!zUV9=TKS<~TO|oCG#$mLps=
zGYtt^v_+295(h>c(eFb8{}jo94ap)T^Br}uf*=F#EI=HSn9rfK2)1RY(>TeJRgHy+
zLaoP`W3*~!XvR_5Dz70|XVlwb4T=aPOtd%@{wb%p<oLXMkSXyF4~bH|$UGS-F>HO5
z)JPy!^W#_2SQ^D_o=JoyTVcc`naDNOxN?-KGPM*oPArTCQo*wVu^jqLc+rCSZCOww
z&@+%2KcL|3%Uq1K%Q53pdPu#-Khdd4xG9cg_?qfBTMUNd0GTBv3YU0gwGzRB%3S(^
z`;N10Ayl=tU@!uM-cBh#AymK9(xsq+tOFZ)k++z55u6V#B=DqClOr*xu=zi@Ah<~_
zD#;3k-QVLHA+9QAP<{F4I3Msnw?XmJhFOV`0Qo}pXigJoZjHWpt_TeH!7=7tlIrjw
zm*3MS5f?+ea&veh<zu95kj(!|V9(*fB+wT^bnJ3-mZQMr%ojpg4q|ibvQV>R8<5be
z$l`nwjv0Hq*GXqt`S=Nn!(bVKZ1S1~_eIPyM%t8xL3y`<Y=yx6E{@2DkBI|nT6sFj
z0AvgkD$NvO+`PtY*c>V}`qkh2xAVLO8WFCBIZW7xu8wKB3XnH0shir}1Q-py-`A7p
zY})ad&(7Vl(%p~68e8zRxY|vZ&oh9CNz;>Cx~i%dt(ljm%ybS8)WS*`mE$_$si^s8
zPn{&4%#BavmJZe*`{8a0_avCliOgDcz~GP3ckWL1#`wm1rfbK?%t;v%W>>@cZpyRt
zt!(FY)pFm)GyLTe+AZN1P+LdIY1fT`7NJ^LYYEpBhxX={_ZEVhr&S04g;b-4FV_y)
zErd-QubM9p-TTW-6TP(@Q7g~fbOR0IXbyrUA1`{{RV-pBXy@J9SYW9?2Y=c(0EtdQ
z4<WG68LWJAU+R!GTF;_xLe}v>Dv?!2*TS--KNtS=8Cew*(d&qEZT93)u-8rHc&6pe
zio!N!H@<|-S$t8G>bcHz;Ad}zbicvPH8QmM8}3gP{RF{}u*GD-uUvyta%*o!og&)D
zGudy{bzlo5+gy3f;PZS4=c*l4ag#C%x?wpVu3Fem#(d${*yo#$<(@RW+KHOo4GfIE
z9S<mvEv~;<@wI@<tsmI`=g`rBAb_C$Ie22AWCcxF$;2mab|`TvUKQ?ee2zqB9x6bp
zUT>)X<4~gVnEAP^ZnRFQc+QjPQ=RkeZO!aXn`}n?n3;dn+k(%2`R8S4F5u(%on%@U
zB!^p{NQyDX$nM;>k*)_TTG4J&IHd<BICV_fwm~fiPTa8(nShXQa)?l7G?DoSjdJ18
z0>(U*&eO15D-AYt#dwOeZ)1$iSOf4OMS)ltM;`0p4Y6XB65b3Y@&eK_`nV9K-Qj_v
zgNBfe9lDeRdo6#jFe8DZfY-OoT3eJF$~%GNkaP#+9jDNNe$No4R4o*?xlmkcB*Ysm
z^uFc9%VoEh9!Jg9Cbh;|WN21raMNe_=BbEv<|6;TZPIM(z`~Cq9gl1>@CFccFd%Gv
zA~PmoF_qQIxHuT_JyY84C1;6^=BYn3yQc7DYguY(y0hjT%~pe_Z)TZW>!_rUY`+ZJ
z8J-p<Lv2CmD?A-<FQi%UfmGiAa~ol&PGDT#A>BhUY~m11xXLo2c={etoP*>hNUTqe
zrhm8iNrld^wNE#_QyPHZ)ecaR!|ysQ))?M^+=q25LRtj$pP<5~+&F8-Xwx9RjDTS9
zB^mK@cj~F|X>^#H!@H(3{Fza`O|C}{(ePCrh<*(SrFAAZCAi}4Gsuhrg$9nK&JrxU
zlEv&Z|2WX9!ALz$rxTn5@>7`}FtHi-&-5!-&8XjJ*xi!4jsL8Kvjx!U3<dOmX4Zzs
zLC>8n_<X7w4D3aO9wgrR)ZmCPyAs+2&;H$bIO9M5vHgm*Dmon~pnRkPeLaP(3LttG
z@O^c!GDndXmo|Be%mBiJI4|4F6K-GgD1@{u<9w5Y=9=f?4Qn`-Zf1l07Jvy-IPLZ?
zp((HgGGCoo)c~NLegkB>ZtOrJTX!|-KD>Y-(|fSzn-$8XJQZ2b&krhV2CuH;6I57n
zRF=3371**_ao89Bbx{6w(C4@c<L_p$qrY5d%!?k+;9`j#mMhIeDup)I+(=;a<XoAy
zizt`Tt4H1^P+sEd+%L;UG~GV2G-@7P#GKI2pPU=CO~RD{qth|y{x?-EH{)4f%u%g$
z==L<XAQ$aVZWm{VUnx+WJ+6Y?E5oZ{(1;X}T5GF*9^SN|xs)^be`{DRng2#Qt9~TS
zpKH%H?L>syob;8;H*d+-c}y0x)&{izXce^s3%9*@P^3~F6cJA8UDj>CSYJg6QvL{Y
zMo+QlY8ACZLijTf=oL66uJaQB!e5|&E=ODne5zs(-<wS{Xx}u4iEV0wpLe>G{H1?+
z$lv(OdaA46>Vpcw_Isk@ev&2p8}0FZIPZ87e4U7uD_v?|xi5hXbK~QHbKvq}Tox^v
z+ZiIqy98LOE5TOzYFhyt%XI9%CCcl8Z2kf@ws2ax+L~!hLHEND;T8t`ji0RggyXZ>
z=cSpD0n<w@+RD$L)^sI6uP&q9zNK^As=e0$dcO3-5d7B62bcfj)0FEWEmsuyWEX>>
zzS3mfft7-vo{qUPW$kyR*(d0eX#Zom-hJIXca;f-b_vG*NdY{}&C{%F`auC~Ro5fg
zXL*iu%~j!8AtS%y(+C4FmIVn43n8`xnPWPV0m2FCf)@N9@5D9ce4x<Ra0=XCqVYiW
zyF<>@dxn=!{wG}7%3H5_n<=~UGCzJ}Yz2+u_=hhf^FWcOZdMxI1+D%TCPThd2e*t|
z_y3~~{+nrz^*{miOnGY?w?CHYXEF^R0#K^_r?#O45>%Po4g`tca1b7H9M|m|k<tz%
z!X+T%NJg-JMmAc0nmF0dBs&i$<sVZFenTZVa14xA8To&p#03UpnLuoC|7iY4p*-N>
z1_C?gACZ+Uea>d79WWv*PbNW?e~LAn28A9*rr!p~GyM#+^C&z}<*NXVN~FqzPGEGG
zV9Ry?FzV`bJrg;Ap$NIq$0+`Tj5Pnh*rn>cA4p|96Ucb_KdfKJ{wHhre}Gk}%7ZM*
z;(h;ZTJ^N<f763vvw(s+$0%e5;{gAM|59#Or%(u~9Y_j02bOGg0tfI|1_9jvwfIhB
z@T=%}ZK<qggx^Pw(7P%qw*5u|8I3;j-hZ`m)?ra?TL6clVSu4?=oXZe%LoY44T6ZI
z(hS0Yv<wWF4v`qT9J&-xS{zD3KvF_Fr1OGO!oZu+@4kEA_r3GqIlI={d!O}NJH92`
zx=dC^9&kF#t$;s3Dh9IX4`W>+5#|KX#Ld^H0k~CSe7N{p$1tI=Et7E4+HM;Dj`@T1
zAwjVam(L%QXAp?*#N#RtnnC@@6c5tN&(^kyyIpJ9YyGUG;VD&>iFo+}KZpsHBVKFh
znL;@IL23`W#joZYl)7IjBev6rU-Ujip8sI4r&*%N+V$vcXMCb>2s0sCAPWJ(29+9q
zwA|;GnTuVT-&Xm?)%{$wS0`gYOy@`EfjxLlDx#rKp&zkj>x));!(7p55}lCKYlFub
zWWv;ly4F4vks*I8LqaK9w0uc<byx{{5ns<KIh^9Sdm=1^X=gL%D&bNJjN&Aj@ZCM&
zh2HV`ZkOL~oViFhw>LOPwm<%tzDMJvE25nDXuJ|toL+mrv(wmgVN@B#4ur_U&pl<a
zCp4r<2t?ClhbbW()}Is`Lfy;t4A_iLme=I@uH@raltW<@5im^2&j1Bi%1jn~Xh&rq
z8wrW~Zg^wn76RMF$M^k8#)&oH>N1_9L7Pjw&)2f3Lh(RW+eaYhC*aMBP)>KA`lMGB
zL?{8^^_?#zOIQ5Vp~FB|air%(A^u{S8)>8fr=7gRgzg)Mw7#04;831$Q-Ye;51f7!
zlNSV`3*{}pBVVd8BB~?N@)5<#Z=G_}PNOTW+q(6fR(Ad0sHc#e;;Z{ab6DKaS^O%9
z5dmKr+*ex+`#I?YyWQgA)8scnQ*Y$vuQ8A)E>q9GvIpgLcMmcYT>gv!TE#O>ebEUj
z)oXkqrsczxh{?;2`&h9Sv~q@5fjGNMUm+wT@z}}qnzaBl2*FT@8I0y`hd<_sx1*lk
z%3oeBaQRl$9C=?q%ZheL3rXZW6?8>bup@yP{!-$)FExOOCf8ZfTEvjlTC1`Gh-T>T
z*!LiV)NhdN36$>VS!N-t)xn6{fI-<pmLOh1IOnxLCBa5!Z%pFoIQYX(3sr*rR@|oN
zw&I)(ILITH&mn0Tz;alA(L;BdV9<7ba=0d~wFt=j1M3gztH8Eze)0C1+2LPEjuH(J
zd?+89O~Dc+8ZmJ8mg(J@3mS4{-(*{!5vNoHLqBP|>nkNC(H(0k8cxuAs~D-Tp@4ur
zS%T#IJ;yNjWegISeMs+kdqHM8l)k`kQ{$5;ur1jdS39svez(d#MPO(^SVx|F|A|(I
zl2H3(daV!*&aKcIrtR=uu&gNcT{ujxd%S0P*10F#g>_2djveD*s_#h@YaNqj?FGH?
z7aAJWwFQF4Q^3KF{c(rG(Oq2@B)KLRJ|Xgkrl4HOP1}y8kH=P`_CPg=kAXhD0C31(
zsFiea1KMV9M?HG~?DBv=frEA**3)M5<j{#xq50)~4}^RNGEUQgNh|PH$keQ(>XdrE
z$d;B~acNw26ICG+d8k=~xLx(=$IsM}6PRkKYmJ{&yz4y|N&WuirjnaG@rbonv#9ei
zkUp>7;0B}1O=VQvMf#>$aoPJ8)<Q!vR5)rjB8b%a)l!@L&6AS{FNLpmOubP-q1W#{
z!OomJc8K6Nnd`K{b&#SxnYRlqOp=L*w&2x3R1$~4<ejfdBll_+5M4crF?`rp|2V~5
zso^ji_Y_F|P<Nz;nBnU$`9>bKqjqogwPQ|*8EGB~mW9jIwL^RB8I>lBF2e3o9Lq|~
zI);e44Q0j82AI?WMnW~6HV<4gZ@<cqlF89fYks*j%unX$>|B_YtD!cqt#x__8-l<U
z&Zx8pK@l0Ym^$N|n;3H*J8^uW+v3{GE+k5m5zD?A>7e1b9wQ^g#?`_&VzkJY(+2g0
z1&Nvb0;cjrs}>GC<>{GNWNyEP(bhoUs|US|&4JRT_$-P7GLd-P1@2hzAgOiP5%8|{
z(pG$tUsjt<de#9U)qlZZK7IYIfdB_a!7?m{=y!I<lVtHJINz3s)28J^0H(57@@?aQ
zJC8+U85@>RJ}L`@sFT%s;20Q3j^+*zXcCUOKOTp~Vl#JYJZ*X+81Sv?dJV@#eH<Qy
zCZ~lFG!=41v^dgqO0Md)W3$C_f9zaoAgjPusydFPP{?~68gUIm4HgEu=COhdWU&ED
z8FBE^qb4rX#BtL7tJXpj3qlSDMmijiV|{$J!=e5!ap<M}h2BXWSFD`NyitJZUlsG<
z6hQpeKp{Xj%v)oDP}J33Jja|521t}qU`Fv^TYue*6Px4wf5oP$zzUV-6RK?%xlL+@
z>jYAYS{a<Xkwg&U!8Bb|{$KHDkbY8{epub!trLGNSHr>lOW5BXK8^@%_^Vau{CHeh
zkH&CO>eC{Wi-5{CS(WHB;Ie~Bo;ZmC7JR3O|1n2Ck*!{Up^AL^QC~j#t3rh^NHQgZ
z<lf4SdDvN+zH+p9)~*rl9HPae)fr#cfg^4FBwH56A<`dVm{%08vgGu$0nj%jf~d88
zMDS<gn2!T3SIQ@=FfN1;^0=%|dxL<wpiG3V=X%z$><ql>AAF_ThLB^XPB3D_Z$<SH
z3j&`quHzl6t1ZRjkshuC?R6GY$jetu2@gyUSV@E@jTQ4gT8ch;%@oYL^XXMz9r)OY
zO0ck!4BBmoF1`m}f%{OLZ5F<7!pA%eeHddDJt!vx<fiQ9{0s5QCiC&@YE0seiA#@r
zUf3M<2dt*#fI7dkx5jS0SJQ<J#<F*v$mLVd#X9CEKgTcWQ^E-SywE315FP_Gc~+nt
zYg-$nV?M!LVfFDy^YTDK_LJjl<><>xZ4wL6UqPQV$N`G%VV@*ce`+6b#e621n9qAQ
zq{^_aAe&-R=A$J#X%>G32&<aZC~5zi^X1sf;sF1nA$qa=KHKgg%LHlQX?|G3W@;sb
z6rki?-lu|!2tZYmw_0jIdBZ>qamI9!*Zp<EO^6Qcy+eJ3(23}mBSz2E9od#GU=C$<
zYV@-W#r87aQ9Cz>Ew<Sro1%}`S|U4vhKuj_2OVYKP@Psm3QQ{~51d(OOG;8yK3F~N
zns`IK&6m@hn?G>13iZ!F7~e|soT{WEe79)l_12>PgC6?^il5|BtBAH9@M~tOssi00
zCOoaQA#Xce=Qrjye`5}X#T->uF5QswZ_E)DxJqEEKmNj8TO7I9ik2dV<o~Vx&*kNI
zmypj4^byc-aZuzzM5{_h;BBbN;LRSj8=clV6lh1g@enP(nBw9e^K4r#fx9kejv42{
zB@jdg5&8yaT`l{O3bE#+En+u8s%q^0?T~x)zM#0;*f1ZDs)K_H?i^wowdkQr9TVc>
zNd4n6&$De#A=j3IcK$(@lAzfoyM>gdKh{&y_z{6nvkOY0ayJOwAD<<v1n-6Bq|z)e
znL2#&@Lq_{7%}LIFHEcOdM4Gce&2qYH_2iwTeemSy>UJtY--oktuV8Gj1YSmWL1~_
z!ED2T%SY|1%(pc_4MXt%w3dD;HR*tlhZhIH!-mQt#m7d;szn<z<0Fg=!o=w#7WFQv
zi-yA(GrYLllLvQ|t!!6b#KH6eS>g>fEqc#R8NYhO_4Ga)!aN@mJ6thi9KugwOw~<1
zpji#EXJC5v3e~tblgq2YCL$*$LPiEvE>wFSNLLH7O$}vwFoAl3w`Z0-PE$#j!e*?&
z?3$*cRqq5Ii+xnA4Q1Ii+Vj+#7Mv%bBF$W;1+I-7&f(8L=PRH?y4`0-{Gsz?X2uuN
zjkfo?9bI@)*6sW>tH-rdF>>(W+x+@@ef2i^^j<8!w%rg<Nl2D<@j%5I-3HA&U1hd!
z6veZ)%JtJ<Bb)$d@AMwZeTw<68Zq$fg0zMC`o!CgoT?zO?#ESC;|r%iFB|VBjwZW8
z4VBT_BaSML2G<ngE@~_6-Q*7Mo#8?k5Y5r(T1(bJ1(37fxc@pvDm~nN)2}PUl5RMp
z&H#?NC|bm;l`{4vpaN%{&qiUp*&I6v^mxcCYeqzhv7P}y0));!<GhVlVNwCfit>d&
z*8Ph&cA;hdrgTGYiC9Z#wcl4F)kD0}p{c;!%qc2$8*{Z{59?4Ztx_;jlbNbnIxgkI
zaOoSx82DoWC-N7Xedhj>tkyP^6-Bhu*`)Y4g2F|61hY!*Swi)Mj^V=6-`#3DAHTyZ
zeWZk#5-W4u_j0gcuX9j#yx&(-BI`NFdxzDJih@33)fNCRjv$lCgXAaDys**UIej`I
z_mrV&4zko4n4?h{X&~i7C7ruZmXtR4XB1DJC-aQAYNHA1L05e-LyWWm2O}~20KI$7
zws#+BDt%z=V5m&nJ}=q&dcSHh4welkK7Wqj(fORJn=c*iUg;SiWfUGHt*C0VW_xbn
zPjyn~3*-*DqU#OrX`Wr62^J?-6ExeD749hgGtz-Qs?3dw-0(&N`AA*<OGpba6SKW3
z`T9=YC9TjKwX!Jp&&wz|SF3j7@-=ncj(D(%b(1+B+-}F|`{5sz3MKR=w+v1<xqfVN
zYXIA@1M>Hw&OdvAgj2WYPp~PcwRUFQ_=pboS#cnm`s-chR@ry8-Yx(&wItik5I0It
zqe7)*E-8{<**474=5D{crPHj7ViKJ2{PL`;+QtG2=2G3;6}cs-miOm_s!89*e$I+p
zOb-JXjb_YQot~s}a<5OVd?RTk8&XlClqjURU3H{TU?a&m!C}rKNN917mB~CNB@zMl
z(ko<`gB*{As@)cg9R^y{Jf%F2;3QthbgkiE`#JBKtT1s_77BKTJ{)<@OVgF0+N%qV
z5_3{XeMnVY?oCl(X_*!dlw14+R+ZRzO?`%>@S$IW8+lCj!qMr<B76*Lk8~-v!4J;j
zPt|Y46xEznJ@6Qn$(Z*uw|4<JeM2zn|9q;9CXClmzSARoT_Tp${C@RyLbO$43l~N)
zcB{0@Q}f(Zi@-HmS$a%$X&2popj1K!D-syG3>hF0^5%~F$pj9_avGMrM+-~kv>zGc
ziOHDxSriwaz^qz4I`Xvh=Ld>jw{K>{gfTj3`W)F3+u=V$ynN>){TD~tmhU1yrP;j$
zN9Aot4+*jRUP}1vncvzog4dG@ShOrzZR)Ex!o!l!?tTlao^yLPmR+{doy3qQz29gp
z^8VqYo9nf2h1HoClLJsCH(m*}GM#~~xH9U}fDV3!uby8KCl7L5_=)yU7on=ZPn4@K
zFmq&_QT{zA@Bw1DUp3g`Gx<O91d%3|1^}1>ve;6P{h!l6oay}cqpgbEwB#lFy_*cO
zVgT@JBQX$mB)ts?X>7#`C^AOEti;)WEwiv2&q~U8c+~$ck5};k*<!^_^czXbRtyBW
z)_6#`0Sm4M_Ww26|1LLcgH*Iu0QlJ=gRJiYEbWl3)_m;$YkK~jecAzQhy>XGJK?dm
U3H0xDyksY&k_``WD-`$jKWoJ?jsO4v

delta 16856
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

-- 
2.7.4.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to