]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Common/VpdInfoFile.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / Python / Common / VpdInfoFile.py
CommitLineData
e56468c0 1## @file\r
f7496d71 2#\r
e56468c0 3# This package manage the VPD PCD information file which will be generated\r
4# by build tool's autogen.\r
5# The VPD PCD information file will be input for third-party BPDG tool which\r
f7496d71 6# is pointed by *_*_*_VPD_TOOL_GUID in conf/tools_def.txt\r
e56468c0 7#\r
8#\r
9eb87141 9# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r
2e351cbe 10# SPDX-License-Identifier: BSD-2-Clause-Patent\r
e56468c0 11#\r
1ccc4d89 12from __future__ import print_function\r
1be2ed90 13import Common.LongFilePathOs as os\r
e56468c0 14import re\r
15import Common.EdkLogger as EdkLogger\r
16import Common.BuildToolError as BuildToolError\r
17import subprocess\r
2a29017e 18import Common.GlobalData as GlobalData\r
1be2ed90 19from Common.LongFilePathSupport import OpenLongFilePath as open\r
e459de78 20from Common.Misc import SaveFileOnChange\r
25598f8b 21from Common.DataType import *\r
e56468c0 22\r
23FILE_COMMENT_TEMPLATE = \\r
24"""\r
25## @file\r
26#\r
27# THIS IS AUTO-GENERATED FILE BY BUILD TOOLS AND PLEASE DO NOT MAKE MODIFICATION.\r
28#\r
29# This file lists all VPD informations for a platform collected by build.exe.\r
f7496d71
LG
30#\r
31# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r
e56468c0 32# This program and the accompanying materials\r
33# are licensed and made available under the terms and conditions of the BSD License\r
34# which accompanies this distribution. The full text of the license may be found at\r
35# http://opensource.org/licenses/bsd-license.php\r
36#\r
37# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
38# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
39#\r
40\r
41"""\r
42\r
43## The class manage VpdInfoFile.\r
44#\r
45# This file contains an ordered (based on position in the DSC file) list of the PCDs specified in the platform description file (DSC). The Value field that will be assigned to the PCD comes from the DSC file, INF file (if not defined in the DSC file) or the DEC file (if not defined in the INF file). This file is used as an input to the BPDG tool.\r
46# Format for this file (using EBNF notation) is:\r
47# <File> :: = [<CommentBlock>]\r
48# [<PcdEntry>]*\r
49# <CommentBlock> ::= ["#" <String> <EOL>]*\r
50# <PcdEntry> ::= <PcdName> "|" <Offset> "|" <Size> "|" <Value> <EOL>\r
51# <PcdName> ::= <TokenSpaceCName> "." <PcdCName>\r
52# <TokenSpaceCName> ::= C Variable Name of the Token Space GUID\r
53# <PcdCName> ::= C Variable Name of the PCD\r
bc39c5cb 54# <Offset> ::= {TAB_STAR} {<HexNumber>}\r
e56468c0 55# <HexNumber> ::= "0x" (a-fA-F0-9){1,8}\r
56# <Size> ::= <HexNumber>\r
57# <Value> ::= {<HexNumber>} {<NonNegativeInt>} {<QString>} {<Array>}\r
58# <NonNegativeInt> ::= (0-9)+\r
59# <QString> ::= ["L"] <DblQuote> <String> <DblQuote>\r
60# <DblQuote> ::= 0x22\r
61# <Array> ::= {<CArray>} {<NList>}\r
62# <CArray> ::= "{" <HexNumber> ["," <HexNumber>]* "}"\r
63# <NList> ::= <HexNumber> ["," <HexNumber>]*\r
64#\r
65class VpdInfoFile:\r
25598f8b 66\r
f7496d71 67 _rVpdPcdLine = None\r
e56468c0 68 ## Constructor\r
69 def __init__(self):\r
70 ## Dictionary for VPD in following format\r
71 #\r
f7496d71 72 # Key : PcdClassObject instance.\r
e56468c0 73 # @see BuildClassObject.PcdClassObject\r
74 # Value : offset in different SKU such as [sku1_offset, sku2_offset]\r
75 self._VpdArray = {}\r
626bece4 76 self._VpdInfo = {}\r
f7496d71 77\r
e56468c0 78 ## Add a VPD PCD collected from platform's autogen when building.\r
79 #\r
80 # @param vpds The list of VPD PCD collected for a platform.\r
81 # @see BuildClassObject.PcdClassObject\r
82 #\r
83 # @param offset integer value for VPD's offset in specific SKU.\r
84 #\r
ccaa7754 85 def Add(self, Vpd, skuname, Offset):\r
4231a819 86 if (Vpd is None):\r
e56468c0 87 EdkLogger.error("VpdInfoFile", BuildToolError.ATTRIBUTE_UNKNOWN_ERROR, "Invalid VPD PCD entry.")\r
f7496d71 88\r
d943b0c3 89 if not (Offset >= "0" or Offset == TAB_STAR):\r
e56468c0 90 EdkLogger.error("VpdInfoFile", BuildToolError.PARAMETER_INVALID, "Invalid offset parameter: %s." % Offset)\r
f7496d71 91\r
656d2539 92 if Vpd.DatumType == TAB_VOID:\r
d943b0c3 93 if Vpd.MaxDatumSize <= "0":\r
f7496d71 94 EdkLogger.error("VpdInfoFile", BuildToolError.PARAMETER_INVALID,\r
e56468c0 95 "Invalid max datum size for VPD PCD %s.%s" % (Vpd.TokenSpaceGuidCName, Vpd.TokenCName))\r
f7496d71 96 elif Vpd.DatumType in TAB_PCD_NUMERIC_TYPES:\r
5565a8c4 97 if not Vpd.MaxDatumSize:\r
25598f8b 98 Vpd.MaxDatumSize = MAX_SIZE_TYPE[Vpd.DatumType]\r
e56468c0 99 else:\r
d943b0c3 100 if Vpd.MaxDatumSize <= "0":\r
2b8a6c44
LG
101 EdkLogger.error("VpdInfoFile", BuildToolError.PARAMETER_INVALID,\r
102 "Invalid max datum size for VPD PCD %s.%s" % (Vpd.TokenSpaceGuidCName, Vpd.TokenCName))\r
f7496d71 103\r
9eb87141 104 if Vpd not in self._VpdArray:\r
e56468c0 105 #\r
f7496d71 106 # If there is no Vpd instance in dict, that imply this offset for a given SKU is a new one\r
e56468c0 107 #\r
8ac16789
LG
108 self._VpdArray[Vpd] = {}\r
109\r
110 self._VpdArray[Vpd].update({skuname:Offset})\r
f7496d71
LG
111\r
112\r
e56468c0 113 ## Generate VPD PCD information into a text file\r
f7496d71 114 #\r
e56468c0 115 # If parameter FilePath is invalid, then assert.\r
f7496d71 116 # If\r
e56468c0 117 # @param FilePath The given file path which would hold VPD information\r
118 def Write(self, FilePath):\r
4231a819 119 if not (FilePath is not None or len(FilePath) != 0):\r
f7496d71
LG
120 EdkLogger.error("VpdInfoFile", BuildToolError.PARAMETER_INVALID,\r
121 "Invalid parameter FilePath: %s." % FilePath)\r
e56468c0 122\r
e459de78 123 Content = FILE_COMMENT_TEMPLATE\r
d943b0c3 124 Pcds = sorted(self._VpdArray.keys(), key=lambda x: x.TokenCName)\r
e459de78
YZ
125 for Pcd in Pcds:\r
126 i = 0\r
2a29017e
YZ
127 PcdTokenCName = Pcd.TokenCName\r
128 for PcdItem in GlobalData.MixedPcd:\r
129 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:\r
130 PcdTokenCName = PcdItem[0]\r
8ac16789
LG
131 for skuname in self._VpdArray[Pcd]:\r
132 PcdValue = str(Pcd.SkuInfoList[skuname].DefaultValue).strip()\r
e459de78
YZ
133 if PcdValue == "" :\r
134 PcdValue = Pcd.DefaultValue\r
135\r
ccaa7754 136 Content += "%s.%s|%s|%s|%s|%s \n" % (Pcd.TokenSpaceGuidCName, PcdTokenCName, skuname, str(self._VpdArray[Pcd][skuname]).strip(), str(Pcd.MaxDatumSize).strip(), PcdValue)\r
e459de78
YZ
137 i += 1\r
138\r
139 return SaveFileOnChange(FilePath, Content, False)\r
e56468c0 140\r
141 ## Read an existing VPD PCD info file.\r
142 #\r
143 # This routine will read VPD PCD information from existing file and construct\r
144 # internal PcdClassObject array.\r
145 # This routine could be used by third-party tool to parse VPD info file content.\r
146 #\r
147 # @param FilePath The full path string for existing VPD PCD info file.\r
148 def Read(self, FilePath):\r
149 try:\r
150 fd = open(FilePath, "r")\r
151 except:\r
f7496d71
LG
152 EdkLogger.error("VpdInfoFile",\r
153 BuildToolError.FILE_OPEN_FAILURE,\r
e56468c0 154 "Fail to open file %s for written." % FilePath)\r
155 Lines = fd.readlines()\r
156 for Line in Lines:\r
157 Line = Line.strip()\r
158 if len(Line) == 0 or Line.startswith("#"):\r
159 continue\r
f7496d71 160\r
e56468c0 161 #\r
162 # the line must follow output format defined in BPDG spec.\r
163 #\r
164 try:\r
ccaa7754
GL
165 PcdName, SkuId, Offset, Size, Value = Line.split("#")[0].split("|")\r
166 PcdName, SkuId, Offset, Size, Value = PcdName.strip(), SkuId.strip(), Offset.strip(), Size.strip(), Value.strip()\r
e56468c0 167 TokenSpaceName, PcdTokenName = PcdName.split(".")\r
168 except:\r
169 EdkLogger.error("BPDG", BuildToolError.PARSER_ERROR, "Fail to parse VPD information file %s" % FilePath)\r
f7496d71 170\r
e56468c0 171 Found = False\r
f7496d71 172\r
626bece4 173 if (TokenSpaceName, PcdTokenName) not in self._VpdInfo:\r
5695877e
FB
174 self._VpdInfo[(TokenSpaceName, PcdTokenName)] = {}\r
175 self._VpdInfo[(TokenSpaceName, PcdTokenName)][(SkuId, Offset)] = Value\r
9eb87141 176 for VpdObject in self._VpdArray:\r
2a29017e
YZ
177 VpdObjectTokenCName = VpdObject.TokenCName\r
178 for PcdItem in GlobalData.MixedPcd:\r
179 if (VpdObject.TokenCName, VpdObject.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:\r
180 VpdObjectTokenCName = PcdItem[0]\r
9eb87141 181 for sku in VpdObject.SkuInfoList:\r
2a29017e 182 if VpdObject.TokenSpaceGuidCName == TokenSpaceName and VpdObjectTokenCName == PcdTokenName.strip() and sku == SkuId:\r
bc39c5cb
JC
183 if self._VpdArray[VpdObject][sku] == TAB_STAR:\r
184 if Offset == TAB_STAR:\r
f7496d71 185 EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "The offset of %s has not been fixed up by third-party BPDG tool." % PcdName)\r
8ac16789 186 self._VpdArray[VpdObject][sku] = Offset\r
e8a47801 187 Found = True\r
e56468c0 188 if not Found:\r
189 EdkLogger.error("BPDG", BuildToolError.PARSER_ERROR, "Can not find PCD defined in VPD guid file.")\r
f7496d71 190\r
e56468c0 191 ## Get count of VPD PCD collected from platform's autogen when building.\r
192 #\r
f7496d71 193 # @return The integer count value\r
e56468c0 194 def GetCount(self):\r
195 Count = 0\r
196 for OffsetList in self._VpdArray.values():\r
197 Count += len(OffsetList)\r
f7496d71 198\r
e56468c0 199 return Count\r
f7496d71 200\r
e56468c0 201 ## Get an offset value for a given VPD PCD\r
202 #\r
f7496d71 203 # Because BPDG only support one Sku, so only return offset for SKU default.\r
e56468c0 204 #\r
f7496d71 205 # @param vpd A given VPD PCD\r
e56468c0 206 def GetOffset(self, vpd):\r
27c4ceb4 207 if vpd not in self._VpdArray:\r
e56468c0 208 return None\r
f7496d71 209\r
e56468c0 210 if len(self._VpdArray[vpd]) == 0:\r
211 return None\r
f7496d71 212\r
e56468c0 213 return self._VpdArray[vpd]\r
890d8ede
GL
214 def GetVpdInfo(self, arg):\r
215 (PcdTokenName, TokenSpaceName) = arg\r
5695877e 216 return [(sku,offset,value) for (sku,offset),value in self._VpdInfo.get((TokenSpaceName, PcdTokenName)).items()]\r
f7496d71 217\r
e56468c0 218## Call external BPDG tool to process VPD file\r
f7496d71 219#\r
e56468c0 220# @param ToolPath The string path name for BPDG tool\r
221# @param VpdFileName The string path name for VPD information guid.txt\r
f7496d71 222#\r
08dd311f 223def CallExtenalBPDGTool(ToolPath, VpdFileName):\r
4231a819
CJ
224 assert ToolPath is not None, "Invalid parameter ToolPath"\r
225 assert VpdFileName is not None and os.path.exists(VpdFileName), "Invalid parameter VpdFileName"\r
f7496d71 226\r
08dd311f
LG
227 OutputDir = os.path.dirname(VpdFileName)\r
228 FileName = os.path.basename(VpdFileName)\r
229 BaseName, ext = os.path.splitext(FileName)\r
230 OutputMapFileName = os.path.join(OutputDir, "%s.map" % BaseName)\r
231 OutputBinFileName = os.path.join(OutputDir, "%s.bin" % BaseName)\r
f7496d71 232\r
e56468c0 233 try:\r
71f5913e 234 PopenObject = subprocess.Popen(' '.join([ToolPath,\r
f7496d71 235 '-o', OutputBinFileName,\r
e56468c0 236 '-m', OutputMapFileName,\r
08dd311f 237 '-q',\r
e56468c0 238 '-f',\r
71f5913e 239 VpdFileName]),\r
f7496d71 240 stdout=subprocess.PIPE,\r
71f5913e
LG
241 stderr= subprocess.PIPE,\r
242 shell=True)\r
5b0671c1 243 except Exception as X:\r
caf74495 244 EdkLogger.error("BPDG", BuildToolError.COMMAND_FAILURE, ExtraData=str(X))\r
e56468c0 245 (out, error) = PopenObject.communicate()\r
8ddec24d 246 print(out.decode())\r
4231a819 247 while PopenObject.returncode is None :\r
e56468c0 248 PopenObject.wait()\r
f7496d71 249\r
e56468c0 250 if PopenObject.returncode != 0:\r
81aeb946 251 EdkLogger.debug(EdkLogger.DEBUG_1, "Fail to call BPDG tool", str(error.decode()))\r
b28d406b 252 EdkLogger.error("BPDG", BuildToolError.COMMAND_FAILURE, "Fail to execute BPDG tool with exit code: %d, the error message is: \n %s" % \\r
81aeb946 253 (PopenObject.returncode, str(error.decode())))\r
f7496d71 254\r
e56468c0 255 return PopenObject.returncode\r