IntelFsp2Pkg: Add missing OEM status code defines.
[mirror_edk2.git] / IntelFsp2Pkg / Tools / SplitFspBin.py
1 ## @ FspTool.py\r
2 #\r
3 # Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
4 # This program and the accompanying materials are licensed and made available under\r
5 # the terms and conditions of the BSD License that accompanies this distribution.\r
6 # The full text of the license may be found at\r
7 # http://opensource.org/licenses/bsd-license.php.\r
8 #\r
9 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 #\r
12 ##\r
13 \r
14 import os\r
15 import sys\r
16 import uuid\r
17 import copy\r
18 import struct\r
19 import argparse\r
20 from   ctypes import *\r
21 \r
22 """\r
23 This utility supports some operations for Intel FSP image.\r
24 It supports:\r
25     - Split a FSP 2.0 compatibale image into individual FSP-T/M/S/C\r
26         and generate the mapping header file.\r
27 """\r
28 \r
29 class c_uint24(Structure):\r
30     """Little-Endian 24-bit Unsigned Integer"""\r
31     _pack_   = 1\r
32     _fields_ = [\r
33         ('Data', (c_uint8 * 3))\r
34         ]\r
35 \r
36     def __init__(self, val=0):\r
37         self.set_value(val)\r
38 \r
39     def __str__(self, indent=0):\r
40         return '0x%.6x' % self.value\r
41 \r
42     def get_value(self):\r
43         return (\r
44             (self.Data[0]      ) +\r
45             (self.Data[1] <<  8) +\r
46             (self.Data[2] << 16)\r
47             )\r
48 \r
49     def set_value(self, val):\r
50         self.Data[0] = (val      ) & 0xff\r
51         self.Data[1] = (val >>  8) & 0xff\r
52         self.Data[2] = (val >> 16) & 0xff\r
53 \r
54     value = property(get_value, set_value)\r
55 \r
56 class EFI_FIRMWARE_VOLUME_HEADER(Structure):\r
57     _fields_ = [\r
58         ('ZeroVector',                 ARRAY(c_uint8, 16)),\r
59         ('FileSystemGuid',             ARRAY(c_char, 16)),\r
60         ('FvLength',                   c_uint64),\r
61         ('Signature',                  c_uint32),\r
62         ('Attributes',                 c_uint32),\r
63         ('HeaderLength',               c_uint16),\r
64         ('Checksum',                   c_uint16),\r
65         ('ExtHeaderOffset',            c_uint16),\r
66         ('Reserved',                   c_uint8),\r
67         ('Revision',                   c_uint8)\r
68         ]\r
69 \r
70 class EFI_FIRMWARE_VOLUME_EXT_HEADER(Structure):\r
71     _fields_ = [\r
72         ('FvName',                     ARRAY(c_char, 16)),\r
73         ('ExtHeaderSize',              c_uint32)\r
74         ]\r
75 \r
76 class EFI_FFS_INTEGRITY_CHECK(Structure):\r
77     _fields_ = [\r
78         ('Header',                     c_uint8),\r
79         ('File',                       c_uint8)\r
80         ]\r
81 \r
82 class EFI_FFS_FILE_HEADER(Structure):\r
83     _fields_ = [\r
84         ('Name',                       ARRAY(c_char, 16)),\r
85         ('IntegrityCheck',             EFI_FFS_INTEGRITY_CHECK),\r
86         ('Type',                       c_uint8),\r
87         ('Attributes',                 c_uint8),\r
88         ('Size',                       c_uint24),\r
89         ('State',                      c_uint8)\r
90         ]\r
91 \r
92 class EFI_COMMON_SECTION_HEADER(Structure):\r
93     _fields_ = [\r
94         ('Size',                       c_uint24),\r
95         ('Type',                       c_uint8)\r
96         ]\r
97 \r
98 class FSP_INFORMATION_HEADER(Structure):\r
99      _fields_ = [\r
100         ('Signature',                   c_uint32),\r
101         ('HeaderLength',                c_uint32),\r
102         ('Reserved1',                   ARRAY(c_uint8, 3)),\r
103         ('HeaderRevision',              c_uint8),\r
104         ('ImageRevision',               c_uint32),\r
105         ('ImageId',                     c_uint64),\r
106         ('ImageSize',                   c_uint32),\r
107         ('ImageBase',                   c_uint32),\r
108         ('ImageAttribute',              c_uint32),\r
109         ('CfgRegionOffset',             c_uint32),\r
110         ('CfgRegionSize',               c_uint32),\r
111         ('ApiEntryNum',                 c_uint32),\r
112         ('NemInitEntry',                c_uint32),\r
113         ('FspInitEntry',                c_uint32),\r
114         ('NotifyPhaseEntry',            c_uint32),\r
115         ('FspMemoryInitEntry',          c_uint32),\r
116         ('TempRamExitEntry',            c_uint32),\r
117         ('FspSiliconInitEntry',         c_uint32)\r
118     ]\r
119 \r
120 class FspFv:\r
121     HeaderFile = """/*\r
122  *\r
123  * Automatically generated file; DO NOT EDIT.\r
124  * FSP mapping file\r
125  *\r
126  */\r
127 """\r
128     FspNameDict = {\r
129         "0" : "-C.Fv",\r
130         "1" : "-T.Fv",\r
131         "2" : "-M.Fv",\r
132         "3" : "-S.Fv",\r
133     }\r
134 \r
135     def __init__(self, FvBin):\r
136         self.FspFv  = {}\r
137         self.FvList = []\r
138         self.FspBin = FvBin\r
139         hfsp = open (self.FspBin, 'r+b')\r
140         self.FspDat = bytearray(hfsp.read())\r
141         hfsp.close()\r
142 \r
143     def OutputStruct (self, obj, indent = 0):\r
144         max_key_len = 20\r
145         pstr = ('  ' * indent + '{0:<%d} = {1}\n') % max_key_len\r
146         if indent:\r
147             s = ''\r
148         else:\r
149             s = ('  ' * indent + '<%s>:\n') % obj.__class__.__name__\r
150         for field in obj._fields_:\r
151             key = field[0]\r
152             val = getattr(obj, key)\r
153             rep = ''\r
154             \r
155             if not isinstance(val, c_uint24) and isinstance(val, Structure):                \r
156                 s += pstr.format(key, val.__class__.__name__)\r
157                 s += self.OutputStruct (val, indent + 1)                \r
158             else:\r
159                 if type(val) in (int, long):\r
160                     rep = hex(val)\r
161                 elif isinstance(val, str) and (len(val) == 16):\r
162                     rep = str(uuid.UUID(bytes = val))\r
163                 elif isinstance(val, c_uint24):                    \r
164                     rep = hex(val.get_value())\r
165                 elif 'c_ubyte_Array' in str(type(val)):                \r
166                     rep = str(list(bytearray(val)))\r
167                 else:\r
168                     rep = str(val)\r
169                 s += pstr.format(key, rep)\r
170         return s\r
171     \r
172     def PrintFv (self):\r
173         print ("FV LIST:")\r
174         idx = 0\r
175         for (fvh, fvhe, offset) in self.FvList:            \r
176             guid = uuid.UUID(bytes = fvhe.FvName)\r
177             print ("FV%d FV GUID:%s  Offset:0x%08X  Length:0x%08X" % (idx, str(guid), offset, fvh.FvLength))\r
178             idx = idx + 1\r
179         print ("\nFSP LIST:")\r
180         for fsp in self.FspFv:\r
181             print "FSP%s contains FV%s" % (fsp, str(self.FspFv[fsp][1]))\r
182             print "\nFSP%s Info Header:" % fsp\r
183             fih = self.FspFv[fsp][0]            \r
184 \r
185     def AlaignPtr (self, offset, alignment = 8):\r
186         return (offset + alignment - 1) & ~(alignment - 1)\r
187 \r
188     def GetFspInfoHdr (self, fvh, fvhe, fvoffset):\r
189         if fvhe:\r
190             offset = fvh.ExtHeaderOffset + fvhe.ExtHeaderSize\r
191         else:\r
192             offset = fvh.HeaderLength\r
193         offset = self.AlaignPtr(offset)\r
194 \r
195         # Now it should be 1st FFS\r
196         ffs = EFI_FFS_FILE_HEADER.from_buffer (self.FspDat, offset)        \r
197         offset += sizeof(ffs)\r
198         offset = self.AlaignPtr(offset)\r
199 \r
200         # Now it should be 1st Section\r
201         sec = EFI_COMMON_SECTION_HEADER.from_buffer (self.FspDat, offset)\r
202         offset += sizeof(sec)\r
203 \r
204         # Now it should be FSP_INFO_HEADER\r
205         offset += fvoffset\r
206         fih = FSP_INFORMATION_HEADER.from_buffer (self.FspDat, offset)\r
207         if 'FSPH' != bytearray.fromhex('%08X' % fih.Signature)[::-1]:\r
208             return None\r
209 \r
210         return fih\r
211 \r
212     def GetFvHdr (self, offset):\r
213         fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FspDat, offset)\r
214         if '_FVH' != bytearray.fromhex('%08X' % fvh.Signature)[::-1]:\r
215             return None, None\r
216         if fvh.ExtHeaderOffset > 0:\r
217             offset += fvh.ExtHeaderOffset\r
218             fvhe = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FspDat, offset)\r
219         else:\r
220             fvhe = None\r
221         return fvh, fvhe\r
222 \r
223     def GetFvData(self, idx):\r
224         (fvh, fvhe, offset) = self.FvList[idx]\r
225         return self.FspDat[offset:offset+fvh.FvLength]\r
226 \r
227     def CheckFsp (self):\r
228         if len(self.FspFv) == 0:\r
229             return\r
230 \r
231         fih = None\r
232         for fv in self.FspFv:\r
233             if not fih:\r
234                 fih = self.FspFv[fv][0]\r
235             else:\r
236                 newfih = self.FspFv[fv][0]\r
237                 if (newfih.ImageId != fih.ImageId) or (newfih.ImageRevision != fih.ImageRevision):\r
238                     raise Exception("Inconsistent FSP ImageId or ImageRevision detected !")\r
239         return\r
240 \r
241     def WriteFsp(self, dir, name):\r
242         if not name:\r
243             name = self.FspBin\r
244         fspname, ext = os.path.splitext(os.path.basename(name))\r
245         for fv in self.FspFv:\r
246             filename = os.path.join(dir, fspname + fv + ext)\r
247             hfsp = open(filename, 'w+b')\r
248             for fvidx in self.FspFv[fv][1]:\r
249                 hfsp.write (self.GetFvData(fvidx))\r
250             hfsp.close()\r
251 \r
252     def WriteMap(self, dir, hfile):\r
253         if not hfile:\r
254             hfile = os.path.splitext(os.path.basename(self.FspBin))[0] + '.h'\r
255         fspname, ext = os.path.splitext(os.path.basename(hfile))\r
256         filename = os.path.join(dir, fspname + ext)\r
257         hfsp   = open(filename, 'w')\r
258         hfsp.write ('%s\n\n' % self.HeaderFile)\r
259 \r
260         firstfv = True\r
261         for fsp in self.FspFv:\r
262             fih = self.FspFv[fsp][0]\r
263             fvs = self.FspFv[fsp][1]\r
264             if firstfv:\r
265                 IdStr = str(bytearray.fromhex('%016X' % fih.ImageId)[::-1])\r
266                 hfsp.write("#define  FSP_IMAGE_ID    0x%016X        /* '%s' */\n" % (fih.ImageId, IdStr))\r
267                 hfsp.write("#define  FSP_IMAGE_REV   0x%08X \n\n" % fih.ImageRevision)\r
268                 firstfv = False\r
269             hfsp.write ('#define  FSP%s_BASE      0x%08X\n'   % (fsp, fih.ImageBase))\r
270             hfsp.write ('#define  FSP%s_OFFSET    0x%08X\n'   % (fsp, self.FvList[fvs[0]][-1]))\r
271             hfsp.write ('#define  FSP%s_LENGTH    0x%08X\n\n' % (fsp, fih.ImageSize))\r
272         hfsp.close()\r
273 \r
274     def ParseFsp (self):\r
275         self.FspFv  = {}\r
276         flen = 0\r
277         for (fvh, fvhe, offset) in self.FvList:\r
278             fih = self.GetFspInfoHdr (fvh, fvhe, offset)\r
279             if fih:\r
280                 if flen != 0:\r
281                     raise Exception("Incorrect FV size in image !")\r
282                 ftype = str((fih.ImageAttribute >> 28) & 0xF)\r
283                 if ftype not in self.FspNameDict:\r
284                     raise Exception("Unknown Attribute in image !")\r
285                 fname = self.FspNameDict[str(ftype)]\r
286                 if fname in self.FspFv:\r
287                     raise Exception("Multiple '%s' in image !" % fname)\r
288                 self.FspFv[fname] = (copy.deepcopy(fih), [])\r
289                 flen = fih.ImageSize\r
290             if flen > 0:\r
291                 flen = flen - fvh.FvLength\r
292                 if flen < 0:\r
293                     raise Exception("Incorrect FV size in image !")\r
294                 self.FspFv[fname][1].append(self.FvList.index((fvh, fvhe, offset)))\r
295 \r
296     def AddFv(self, offset):\r
297         fvh, fvhe = self.GetFvHdr (offset)\r
298         if fvh is None:\r
299             raise Exception('FV signature is not valid !')\r
300         fvitem = (copy.deepcopy(fvh), copy.deepcopy(fvhe), offset)\r
301         self.FvList.append(fvitem)\r
302         return fvh.FvLength\r
303 \r
304     def ParseFv(self):\r
305         offset = 0\r
306         while (offset < len(self.FspDat)):\r
307             fv_len  = self.AddFv (offset)\r
308             offset += fv_len\r
309 \r
310 def GenFspHdr (fspfile, outdir, hfile, show):\r
311     fsp_fv = FspFv(fspfile)\r
312     fsp_fv.ParseFv()\r
313     fsp_fv.ParseFsp()\r
314     fsp_fv.CheckFsp()\r
315     if show:\r
316         fsp_fv.PrintFv()\r
317     fsp_fv.WriteMap(outdir, hfile)\r
318 \r
319 def SplitFspBin (fspfile, outdir, nametemplate, show):\r
320     fsp_fv = FspFv(fspfile)\r
321     fsp_fv.ParseFv()\r
322     fsp_fv.ParseFsp()\r
323     if show:\r
324         fsp_fv.PrintFv()\r
325     fsp_fv.WriteFsp(outdir, nametemplate)\r
326 \r
327 def main ():\r
328     parser = argparse.ArgumentParser()\r
329     subparsers    = parser.add_subparsers(title='commands')\r
330 \r
331     parser_split  = subparsers.add_parser('split',  help='split a FSP into multiple components')\r
332     parser_split.set_defaults(which='split')\r
333     parser_split.add_argument('-f',  '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)\r
334     parser_split.add_argument('-o',  '--outdir' , dest='OutputDir', type=str, help='Output directory path',   default = '.')\r
335     parser_split.add_argument('-n',  '--nametpl', dest='NameTemplate', type=str, help='Output name template', default = '')\r
336     parser_split.add_argument('-p', action='store_true', help='Print FSP FV information', default = False)\r
337 \r
338     parser_genhdr = subparsers.add_parser('genhdr',  help='generate a header file for FSP binary')\r
339     parser_genhdr.set_defaults(which='genhdr')\r
340     parser_genhdr.add_argument('-f',  '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)\r
341     parser_genhdr.add_argument('-o',  '--outdir' , dest='OutputDir', type=str, help='Output directory path',   default = '.')\r
342     parser_genhdr.add_argument('-n',  '--hfile',   dest='HFileName', type=str, help='Output header file name', default = '')\r
343     parser_genhdr.add_argument('-p', action='store_true', help='Print FSP FV information', default = False)\r
344 \r
345     args = parser.parse_args()\r
346     if args.which in ['split', 'genhdr']:\r
347         if not os.path.exists(args.FspBinary):\r
348             raise Exception ("Could not locate FSP binary file '%s' !" % args.FspBinary)\r
349         if not os.path.exists(args.OutputDir):\r
350             raise Exception ("Invalid output directory '%s' !" % args.OutputDir)\r
351 \r
352     if args.which == 'split':\r
353         SplitFspBin (args.FspBinary, args.OutputDir, args.NameTemplate, args.p)\r
354     elif args.which == 'genhdr':\r
355         GenFspHdr   (args.FspBinary, args.OutputDir, args.HFileName, args.p)\r
356     else:\r
357         pass\r
358 \r
359     print 'Done!'\r
360     return 0\r
361 \r
362 if __name__ == '__main__':\r
363     sys.exit(main())\r