Sync EDKII BaseTools to BaseTools project r1903.
[efi/edk2/.git] / edk2 / BaseTools / Source / Python / GenFds / Fv.py
1 ## @file\r
2 # process FV generation\r
3 #\r
4 #  Copyright (c) 2007 - 2010, 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 BaseAddress == None and 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, FvParentAddr=BaseAddress)\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         OrigFvInfo = None\r
126         if os.path.exists (FvInfoFileName):\r
127             OrigFvInfo = open(FvInfoFileName, 'r').read()\r
128         GenFdsGlobalVariable.GenerateFirmwareVolume(\r
129                                 FvOutputFile,\r
130                                 [self.InfFileName],\r
131                                 AddressFile=FvInfoFileName,\r
132                                 FfsList=FfsFileList\r
133                                 )\r
134 \r
135         NewFvInfo = None\r
136         if os.path.exists (FvInfoFileName):\r
137             NewFvInfo = open(FvInfoFileName, 'r').read()\r
138         if NewFvInfo != None and NewFvInfo != OrigFvInfo:\r
139             FvChildAddr = []\r
140             AddFileObj = open(FvInfoFileName, 'r')\r
141             AddrStrings = AddFileObj.readlines()\r
142             AddrKeyFound = False\r
143             for AddrString in AddrStrings:\r
144                 if AddrKeyFound:\r
145                     #get base address for the inside FvImage\r
146                     FvChildAddr.append (AddrString)\r
147                 elif AddrString.find ("[FV_BASE_ADDRESS]") != -1:\r
148                     AddrKeyFound = True\r
149             AddFileObj.close()\r
150 \r
151             if FvChildAddr != []:\r
152                 # Update Ffs again\r
153                 for FfsFile in self.FfsList :\r
154                     FileName = FfsFile.GenFfs(MacroDict, FvChildAddr, BaseAddress)\r
155                 \r
156                 #Update GenFv again\r
157                 GenFdsGlobalVariable.GenerateFirmwareVolume(\r
158                                         FvOutputFile,\r
159                                         [self.InfFileName],\r
160                                         AddressFile=FvInfoFileName,\r
161                                         FfsList=FfsFileList\r
162                                         )\r
163 \r
164         #\r
165         # Write the Fv contents to Buffer\r
166         #\r
167         FvFileObj = open ( FvOutputFile,'r+b')\r
168 \r
169         GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s FV Successfully" %self.UiFvName)\r
170         GenFdsGlobalVariable.SharpCounter = 0\r
171 \r
172         Buffer.write(FvFileObj.read())\r
173         FvFileObj.seek(0)\r
174         # PI FvHeader is 0x48 byte\r
175         FvHeaderBuffer = FvFileObj.read(0x48)\r
176         # FV alignment position.\r
177         FvAlignmentValue = 1 << (ord (FvHeaderBuffer[0x2E]) & 0x1F)\r
178         # FvAlignmentValue is larger than or equal to 1K\r
179         if FvAlignmentValue >= 0x400:\r
180             if FvAlignmentValue >= 0x10000:\r
181                 #The max alignment supported by FFS is 64K.\r
182                 self.FvAlignment = "64K"\r
183             else:\r
184                 self.FvAlignment = str (FvAlignmentValue / 0x400) + "K"\r
185         else:\r
186             # FvAlignmentValue is less than 1K\r
187             self.FvAlignment = str (FvAlignmentValue)\r
188         FvFileObj.close()\r
189         GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile\r
190         return FvOutputFile\r
191 \r
192     ## __InitializeInf__()\r
193     #\r
194     #   Initilize the inf file to create FV\r
195     #\r
196     #   @param  self        The object pointer\r
197     #   @param  BaseAddress base address of FV\r
198     #   @param  BlockSize   block size of FV\r
199     #   @param  BlockNum    How many blocks in FV\r
200     #   @param  ErasePolarity      Flash erase polarity\r
201     #   @param  VtfDict     VTF objects\r
202     #\r
203     def __InitializeInf__ (self, BaseAddress = None, BlockSize= None, BlockNum = None, ErasePloarity='1', VtfDict=None) :\r
204         #\r
205         # Create FV inf file\r
206         #\r
207         self.InfFileName = os.path.join(GenFdsGlobalVariable.FvDir,\r
208                                    self.UiFvName + '.inf')\r
209         self.FvInfFile = StringIO.StringIO()\r
210 \r
211         #\r
212         # Add [Options]\r
213         #\r
214         self.FvInfFile.writelines("[options]" + T_CHAR_LF)\r
215         if BaseAddress != None :\r
216             self.FvInfFile.writelines("EFI_BASE_ADDRESS = " + \\r
217                                        BaseAddress          + \\r
218                                        T_CHAR_LF)\r
219 \r
220         if BlockSize != None:\r
221             self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \\r
222                                       '0x%X' %BlockSize    + \\r
223                                       T_CHAR_LF)\r
224             if BlockNum != None:\r
225                 self.FvInfFile.writelines("EFI_NUM_BLOCKS   = "  + \\r
226                                       ' 0x%X' %BlockNum    + \\r
227                                       T_CHAR_LF)\r
228         else:\r
229             if self.BlockSizeList == []:\r
230                 #set default block size is 1\r
231                 self.FvInfFile.writelines("EFI_BLOCK_SIZE  = 0x1" + T_CHAR_LF)\r
232             \r
233             for BlockSize in self.BlockSizeList :\r
234                 if BlockSize[0] != None:\r
235                     self.FvInfFile.writelines("EFI_BLOCK_SIZE  = "  + \\r
236                                           '0x%X' %BlockSize[0]    + \\r
237                                           T_CHAR_LF)\r
238 \r
239                 if BlockSize[1] != None:\r
240                     self.FvInfFile.writelines("EFI_NUM_BLOCKS   = "  + \\r
241                                           ' 0x%X' %BlockSize[1]    + \\r
242                                           T_CHAR_LF)\r
243 \r
244         if self.BsBaseAddress != None:\r
245             self.FvInfFile.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \\r
246                                        '0x%X' %self.BsBaseAddress)\r
247         if self.RtBaseAddress != None:\r
248             self.FvInfFile.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \\r
249                                       '0x%X' %self.RtBaseAddress)\r
250         #\r
251         # Add attribute\r
252         #\r
253         self.FvInfFile.writelines("[attributes]" + T_CHAR_LF)\r
254 \r
255         self.FvInfFile.writelines("EFI_ERASE_POLARITY   = "       + \\r
256                                           ' %s' %ErasePloarity    + \\r
257                                           T_CHAR_LF)\r
258         if not (self.FvAttributeDict == None):\r
259             for FvAttribute in self.FvAttributeDict.keys() :\r
260                 self.FvInfFile.writelines("EFI_"            + \\r
261                                           FvAttribute       + \\r
262                                           ' = '             + \\r
263                                           self.FvAttributeDict[FvAttribute] + \\r
264                                           T_CHAR_LF )\r
265         if self.FvAlignment != None:\r
266             self.FvInfFile.writelines("EFI_FVB2_ALIGNMENT_"     + \\r
267                                        self.FvAlignment.strip() + \\r
268                                        " = TRUE"                + \\r
269                                        T_CHAR_LF)\r
270                                        \r
271         #\r
272         # Generate FV extension header file\r
273         #\r
274         if self.FvNameGuid == None or self.FvNameGuid == '':\r
275             if len(self.FvExtEntryType) > 0:\r
276                 GenFdsGlobalVariable.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self.UiFvName))\r
277         \r
278         if self.FvNameGuid <> None and self.FvNameGuid <> '':\r
279             TotalSize = 16 + 4\r
280             Buffer = ''\r
281             for Index in range (0, len(self.FvExtEntryType)):\r
282                 if self.FvExtEntryType[Index] == 'FILE':\r
283                     # check if the path is absolute or relative
284                     if os.path.isabs(self.FvExtEntryData[Index]):
285                         FileFullPath = os.path.normpath(self.FvExtEntryData[Index])
286                     else:
287                         FileFullPath = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.FvExtEntryData[Index]))
288                     # check if the file path exists or not
289                     if not os.path.isfile(FileFullPath):
290                         GenFdsGlobalVariable.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self.FvExtEntryData[Index]))\r
291                     FvExtFile = open (FileFullPath,'rb')\r
292                     FvExtFile.seek(0,2)\r
293                     Size = FvExtFile.tell()\r
294                     if Size >= 0x10000:\r
295                         GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self.FvExtEntryData[Index]))\r
296                     TotalSize += (Size + 4)\r
297                     FvExtFile.seek(0)\r
298                     Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))\r
299                     Buffer += FvExtFile.read() \r
300                     FvExtFile.close()\r
301                 if self.FvExtEntryType[Index] == 'DATA':\r
302                     ByteList = self.FvExtEntryData[Index].split(',')\r
303                     Size = len (ByteList)\r
304                     if Size >= 0x10000:\r
305                         GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self.FvExtEntryData[Index]))\r
306                     TotalSize += (Size + 4)\r
307                     Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))\r
308                     for Index1 in range (0, Size):\r
309                         Buffer += pack('B', int(ByteList[Index1], 16))\r
310 \r
311             Guid = self.FvNameGuid.split('-')\r
312             Buffer = pack('LHHBBBBBBBBL', \r
313                         int(Guid[0], 16), \r
314                         int(Guid[1], 16), \r
315                         int(Guid[2], 16), \r
316                         int(Guid[3][-4:-2], 16), \r
317                         int(Guid[3][-2:], 16),  \r
318                         int(Guid[4][-12:-10], 16),\r
319                         int(Guid[4][-10:-8], 16),\r
320                         int(Guid[4][-8:-6], 16),\r
321                         int(Guid[4][-6:-4], 16),\r
322                         int(Guid[4][-4:-2], 16),\r
323                         int(Guid[4][-2:], 16),\r
324                         TotalSize\r
325                         ) + Buffer\r
326 \r
327             #\r
328             # Generate FV extension header file if the total size is not zero\r
329             #\r
330             if TotalSize > 0:\r
331                 FvExtHeaderFileName = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName + '.ext')\r
332                 FvExtHeaderFile = StringIO.StringIO()\r
333                 FvExtHeaderFile.write(Buffer)\r
334                 Changed = SaveFileOnChange(FvExtHeaderFileName, FvExtHeaderFile.getvalue(), True)\r
335                 FvExtHeaderFile.close()\r
336                 if Changed:\r
337                   if os.path.exists (self.InfFileName):\r
338                     os.remove (self.InfFileName)\r
339                 self.FvInfFile.writelines("EFI_FV_EXT_HEADER_FILE_NAME = "      + \\r
340                                            FvExtHeaderFileName                  + \\r
341                                            T_CHAR_LF)\r
342 \r
343          \r
344         #\r
345         # Add [Files]\r
346         #\r
347         self.FvInfFile.writelines("[files]" + T_CHAR_LF)\r
348         if VtfDict != None and self.UiFvName in VtfDict.keys():\r
349             self.FvInfFile.writelines("EFI_FILE_NAME = "                   + \\r
350                                        VtfDict.get(self.UiFvName)          + \\r
351                                        T_CHAR_LF)\r