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