Sync tool code to BuildTools project r1739.
[efi/edk2/.git] / edk2 / BaseTools / Source / Python / GenFds / Fv.py
1 ## @file\r
2 # process FV generation\r
3 #\r
4 #  Copyright (c) 2007, Intel Corporation\r
5 #\r
6 #  All rights reserved. This program and the accompanying materials\r
7 #  are licensed and made available under the terms and conditions of the BSD License\r
8 #  which accompanies this distribution.  The full text of the license may be found at\r
9 #  http://opensource.org/licenses/bsd-license.php\r
10 #\r
11 #  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 #  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 #\r
14 \r
15 ##\r
16 # Import Modules\r
17 #\r
18 import os\r
19 import shutil\r
20 import subprocess\r
21 import StringIO\r
22 from struct import *\r
23 \r
24 import Ffs\r
25 import AprioriSection\r
26 from GenFdsGlobalVariable import GenFdsGlobalVariable\r
27 from GenFds import GenFds\r
28 from CommonDataClass.FdfClass import FvClassObject\r
29 from Common.Misc import SaveFileOnChange\r
30 \r
31 T_CHAR_LF = '\n'\r
32 \r
33 ## generate FV\r
34 #\r
35 #\r
36 class FV (FvClassObject):\r
37     ## The constructor\r
38     #\r
39     #   @param  self        The object pointer\r
40     #\r
41     def __init__(self):\r
42         FvClassObject.__init__(self)\r
43         self.FvInfFile = None\r
44         self.FvAddressFile = None\r
45         self.BaseAddress = None\r
46         self.InfFileName = None\r
47         self.FvAddressFileName = None\r
48         self.CapsuleName = None\r
49 \r
50     ## AddToBuffer()\r
51     #\r
52     #   Generate Fv and add it to the Buffer\r
53     #\r
54     #   @param  self        The object pointer\r
55     #   @param  Buffer      The buffer generated FV data will be put\r
56     #   @param  BaseAddress base address of FV\r
57     #   @param  BlockSize   block size of FV\r
58     #   @param  BlockNum    How many blocks in FV\r
59     #   @param  ErasePolarity      Flash erase polarity\r
60     #   @param  VtfDict     VTF objects\r
61     #   @param  MacroDict   macro value pair\r
62     #   @retval string      Generated FV file path\r
63     #\r
64     def AddToBuffer (self, Buffer, BaseAddress=None, BlockSize= None, BlockNum=None, ErasePloarity='1', VtfDict=None, MacroDict = {}) :\r
65 \r
66         if self.UiFvName.upper() + 'fv' in GenFds.ImageBinDict.keys():\r
67             return GenFds.ImageBinDict[self.UiFvName.upper() + 'fv']\r
68         \r
69         #\r
70         # Check whether FV in Capsule is in FD flash region.\r
71         # If yes, return error. Doesn't support FV in Capsule image is also in FD flash region.\r
72         #\r
73         if self.CapsuleName != None:\r
74             for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():\r
75                 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]\r
76                 for RegionObj in FdObj.RegionList:\r
77                     if RegionObj.RegionType == 'FV':\r
78                         for RegionData in RegionObj.RegionDataList:\r
79                             if RegionData.endswith(".fv"):\r
80                                 continue\r
81                             elif RegionData.upper() + 'fv' in GenFds.ImageBinDict.keys():\r
82                                 continue\r
83                             elif self.UiFvName.upper() == RegionData.upper():\r
84                                GenFdsGlobalVariable.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self.CapsuleName, self.UiFvName.upper()))\r
85 \r
86         GenFdsGlobalVariable.InfLogger( "\nGenerating %s FV" %self.UiFvName)\r
87 \r
88         self.__InitializeInf__(BaseAddress, BlockSize, BlockNum, ErasePloarity, VtfDict)\r
89         #\r
90         # First Process the Apriori section\r
91         #\r
92         MacroDict.update(self.DefineVarDict)\r
93 \r
94         GenFdsGlobalVariable.VerboseLogger('First generate Apriori file !')\r
95         FfsFileList = []\r
96         for AprSection in self.AprioriSectionList:\r
97             FileName = AprSection.GenFfs (self.UiFvName, MacroDict)\r
98             FfsFileList.append(FileName)\r
99             # Add Apriori file name to Inf file\r
100             self.FvInfFile.writelines("EFI_FILE_NAME = " + \\r
101                                        FileName          + \\r
102                                            T_CHAR_LF)\r
103 \r
104         # Process Modules in FfsList\r
105         for FfsFile in self.FfsList :\r
106             FileName = FfsFile.GenFfs(MacroDict)\r
107             FfsFileList.append(FileName)\r
108             self.FvInfFile.writelines("EFI_FILE_NAME = " + \\r
109                                        FileName          + \\r
110                                        T_CHAR_LF)\r
111 \r
112         SaveFileOnChange(self.InfFileName, self.FvInfFile.getvalue(), False)\r
113         self.FvInfFile.close()\r
114         #\r
115         # Call GenFv tool\r
116         #\r
117         FvOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName)\r
118         FvOutputFile = FvOutputFile + '.Fv'\r
119         # BUGBUG: FvOutputFile could be specified from FDF file (FV section, CreateFile statement)\r
120         if self.CreateFileName != None:\r
121             FvOutputFile = self.CreateFileName\r
122 \r
123         FvInfoFileName = os.path.join(GenFdsGlobalVariable.FfsDir, self.UiFvName + '.inf')\r
124         shutil.copy(GenFdsGlobalVariable.FvAddressFileName, FvInfoFileName)\r
125         GenFdsGlobalVariable.GenerateFirmwareVolume(\r
126                                 FvOutputFile,\r
127                                 [self.InfFileName],\r
128                                 AddressFile=FvInfoFileName,\r
129                                 FfsList=FfsFileList\r
130                                 )\r
131 \r
132         #\r
133         # Write the Fv contents to Buffer\r
134         #\r
135         FvFileObj = open ( FvOutputFile,'r+b')\r
136 \r
137         GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s FV Successfully" %self.UiFvName)\r
138         GenFdsGlobalVariable.SharpCounter = 0\r
139 \r
140         Buffer.write(FvFileObj.read())\r
141         FvFileObj.close()\r
142         GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile\r
143         return FvOutputFile\r
144 \r
145     ## __InitializeInf__()\r
146     #\r
147     #   Initilize the inf file to create FV\r
148     #\r
149     #   @param  self        The object pointer\r
150     #   @param  BaseAddress base address of FV\r
151     #   @param  BlockSize   block size of FV\r
152     #   @param  BlockNum    How many blocks in FV\r
153     #   @param  ErasePolarity      Flash erase polarity\r
154     #   @param  VtfDict     VTF objects\r
155     #\r
156     def __InitializeInf__ (self, BaseAddress = None, BlockSize= None, BlockNum = None, ErasePloarity='1', VtfDict=None) :\r
157         #\r
158         # Create FV inf file\r
159         #\r
160         self.InfFileName = os.path.join(GenFdsGlobalVariable.FvDir,\r
161                                    self.UiFvName + '.inf')\r
162         self.FvInfFile = StringIO.StringIO()\r
163 \r
164         #\r
165         # Add [Options]\r
166         #\r
167         self.FvInfFile.writelines("[options]" + T_CHAR_LF)\r
168         if BaseAddress != None :\r
169             self.FvInfFile.writelines("EFI_BASE_ADDRESS = " + \\r
170                                        BaseAddress          + \\r
171                                        T_CHAR_LF)\r
172 \r
173         if BlockSize != None:\r
174             self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \\r
175                                       '0x%X' %BlockSize    + \\r
176                                       T_CHAR_LF)\r
177             if BlockNum != None:\r
178                 self.FvInfFile.writelines("EFI_NUM_BLOCKS   = "  + \\r
179                                       ' 0x%X' %BlockNum    + \\r
180                                       T_CHAR_LF)\r
181         else:\r
182             for BlockSize in self.BlockSizeList :\r
183                 if BlockSize[0] != None:\r
184                     self.FvInfFile.writelines("EFI_BLOCK_SIZE  = "  + \\r
185                                           '0x%X' %BlockSize[0]    + \\r
186                                           T_CHAR_LF)\r
187 \r
188                 if BlockSize[1] != None:\r
189                     self.FvInfFile.writelines("EFI_NUM_BLOCKS   = "  + \\r
190                                           ' 0x%X' %BlockSize[1]    + \\r
191                                           T_CHAR_LF)\r
192 \r
193         if self.BsBaseAddress != None:\r
194             self.FvInfFile.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \\r
195                                        '0x%X' %self.BsBaseAddress)\r
196         if self.RtBaseAddress != None:\r
197             self.FvInfFile.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \\r
198                                       '0x%X' %self.RtBaseAddress)\r
199         #\r
200         # Add attribute\r
201         #\r
202         self.FvInfFile.writelines("[attributes]" + T_CHAR_LF)\r
203 \r
204         self.FvInfFile.writelines("EFI_ERASE_POLARITY   = "       + \\r
205                                           ' %s' %ErasePloarity    + \\r
206                                           T_CHAR_LF)\r
207         if not (self.FvAttributeDict == None):\r
208             for FvAttribute in self.FvAttributeDict.keys() :\r
209                 self.FvInfFile.writelines("EFI_"            + \\r
210                                           FvAttribute       + \\r
211                                           ' = '             + \\r
212                                           self.FvAttributeDict[FvAttribute] + \\r
213                                           T_CHAR_LF )\r
214         if self.FvAlignment != None:\r
215             self.FvInfFile.writelines("EFI_FVB2_ALIGNMENT_"     + \\r
216                                        self.FvAlignment.strip() + \\r
217                                        " = TRUE"                + \\r
218                                        T_CHAR_LF)\r
219                                        \r
220         #\r
221         # Generate FV extension header file\r
222         #\r
223         if self.FvNameGuid == None or self.FvNameGuid == '':\r
224             if len(self.FvExtEntryType) > 0:\r
225                 GenFdsGlobalVariable.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self.UiFvName))\r
226         \r
227         if self.FvNameGuid <> None and self.FvNameGuid <> '':\r
228             TotalSize = 16 + 4\r
229             Buffer = ''\r
230             for Index in range (0, len(self.FvExtEntryType)):\r
231                 if self.FvExtEntryType[Index] == 'FILE':\r
232                     # check if the path is absolute or relative
233                     if os.path.isabs(self.FvExtEntryData[Index]):
234                         FileFullPath = os.path.normpath(self.FvExtEntryData[Index])
235                     else:
236                         FileFullPath = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.FvExtEntryData[Index]))
237                     # check if the file path exists or not
238                     if not os.path.isfile(FileFullPath):
239                         GenFdsGlobalVariable.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self.FvExtEntryData[Index]))\r
240                     FvExtFile = open (FileFullPath,'rb')\r
241                     FvExtFile.seek(0,2)\r
242                     Size = FvExtFile.tell()\r
243                     if Size >= 0x10000:\r
244                         GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self.FvExtEntryData[Index]))\r
245                     TotalSize += (Size + 4)\r
246                     FvExtFile.seek(0)\r
247                     Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))\r
248                     Buffer += FvExtFile.read() \r
249                     FvExtFile.close()\r
250                 if self.FvExtEntryType[Index] == 'DATA':\r
251                     ByteList = self.FvExtEntryData[Index].split(',')\r
252                     Size = len (ByteList)\r
253                     if Size >= 0x10000:\r
254                         GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self.FvExtEntryData[Index]))\r
255                     TotalSize += (Size + 4)\r
256                     Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))\r
257                     for Index1 in range (0, Size):\r
258                         Buffer += pack('B', int(ByteList[Index1], 16))\r
259 \r
260             Guid = self.FvNameGuid.split('-')\r
261             Buffer = pack('LHHBBBBBBBBL', \r
262                         int(Guid[0], 16), \r
263                         int(Guid[1], 16), \r
264                         int(Guid[2], 16), \r
265                         int(Guid[3][-4:-2], 16), \r
266                         int(Guid[3][-2:], 16),  \r
267                         int(Guid[4][-12:-10], 16),\r
268                         int(Guid[4][-10:-8], 16),\r
269                         int(Guid[4][-8:-6], 16),\r
270                         int(Guid[4][-6:-4], 16),\r
271                         int(Guid[4][-4:-2], 16),\r
272                         int(Guid[4][-2:], 16),\r
273                         TotalSize\r
274                         ) + Buffer\r
275 \r
276             #\r
277             # Generate FV extension header file if the total size is not zero\r
278             #\r
279             if TotalSize > 0:\r
280                 FvExtHeaderFileName = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName + '.ext')\r
281                 FvExtHeaderFile = open (FvExtHeaderFileName,'wb')\r
282                 FvExtHeaderFile.write(Buffer)\r
283                 FvExtHeaderFile.close()\r
284                 self.FvInfFile.writelines("EFI_FV_EXT_HEADER_FILE_NAME = "      + \\r
285                                            FvExtHeaderFileName                  + \\r
286                                            T_CHAR_LF)\r
287 \r
288          \r
289         #\r
290         # Add [Files]\r
291         #\r
292         self.FvInfFile.writelines("[files]" + T_CHAR_LF)\r
293         if VtfDict != None and self.UiFvName in VtfDict.keys():\r
294             self.FvInfFile.writelines("EFI_FILE_NAME = "                   + \\r
295                                        VtfDict.get(self.UiFvName)          + \\r
296                                        T_CHAR_LF)\r