Add IntelFsp2Pkg and IntelFsp2WrapperPkg.
[mirror_edk2.git] / IntelFsp2Pkg / Tools / SplitFspBin.py
CommitLineData
cf1d4549
JY
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
14import os\r
15import sys\r
16import uuid\r
17import copy\r
18import struct\r
19import argparse\r
20from ctypes import *\r
21\r
22"""\r
23This utility supports some operations for Intel FSP image.\r
24It 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
29class 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
56class 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
70class 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
76class EFI_FFS_INTEGRITY_CHECK(Structure):\r
77 _fields_ = [\r
78 ('Header', c_uint8),\r
79 ('File', c_uint8)\r
80 ]\r
81\r
82class 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
92class EFI_COMMON_SECTION_HEADER(Structure):\r
93 _fields_ = [\r
94 ('Size', c_uint24),\r
95 ('Type', c_uint8)\r
96 ]\r
97\r
98class 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
120class 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
310def 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
319def 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
327def 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
362if __name__ == '__main__':\r
363 sys.exit(main())\r