SplitFspBin.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. ## @ SplitFspBin.py
  2. #
  3. # Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>
  4. # SPDX-License-Identifier: BSD-2-Clause-Patent
  5. #
  6. ##
  7. import os
  8. import sys
  9. import uuid
  10. import copy
  11. import struct
  12. import argparse
  13. from ctypes import *
  14. from functools import reduce
  15. """
  16. This utility supports some operations for Intel FSP 1.x/2.x image.
  17. It supports:
  18. - Display FSP 1.x/2.x information header
  19. - Split FSP 2.x image into individual FSP-T/M/S/O component
  20. - Rebase FSP 1.x/2.x components to a different base address
  21. - Generate FSP 1.x/2.x mapping C header file
  22. """
  23. CopyRightHeaderFile = """/*
  24. *
  25. * Automatically generated file; DO NOT EDIT.
  26. * FSP mapping file
  27. *
  28. */
  29. """
  30. class c_uint24(Structure):
  31. """Little-Endian 24-bit Unsigned Integer"""
  32. _pack_ = 1
  33. _fields_ = [('Data', (c_uint8 * 3))]
  34. def __init__(self, val=0):
  35. self.set_value(val)
  36. def __str__(self, indent=0):
  37. return '0x%.6x' % self.value
  38. def __int__(self):
  39. return self.get_value()
  40. def set_value(self, val):
  41. self.Data[0:3] = Val2Bytes(val, 3)
  42. def get_value(self):
  43. return Bytes2Val(self.Data[0:3])
  44. value = property(get_value, set_value)
  45. class EFI_FIRMWARE_VOLUME_HEADER(Structure):
  46. _fields_ = [
  47. ('ZeroVector', ARRAY(c_uint8, 16)),
  48. ('FileSystemGuid', ARRAY(c_uint8, 16)),
  49. ('FvLength', c_uint64),
  50. ('Signature', ARRAY(c_char, 4)),
  51. ('Attributes', c_uint32),
  52. ('HeaderLength', c_uint16),
  53. ('Checksum', c_uint16),
  54. ('ExtHeaderOffset', c_uint16),
  55. ('Reserved', c_uint8),
  56. ('Revision', c_uint8)
  57. ]
  58. class EFI_FIRMWARE_VOLUME_EXT_HEADER(Structure):
  59. _fields_ = [
  60. ('FvName', ARRAY(c_uint8, 16)),
  61. ('ExtHeaderSize', c_uint32)
  62. ]
  63. class EFI_FFS_INTEGRITY_CHECK(Structure):
  64. _fields_ = [
  65. ('Header', c_uint8),
  66. ('File', c_uint8)
  67. ]
  68. class EFI_FFS_FILE_HEADER(Structure):
  69. _fields_ = [
  70. ('Name', ARRAY(c_uint8, 16)),
  71. ('IntegrityCheck', EFI_FFS_INTEGRITY_CHECK),
  72. ('Type', c_uint8),
  73. ('Attributes', c_uint8),
  74. ('Size', c_uint24),
  75. ('State', c_uint8)
  76. ]
  77. class EFI_COMMON_SECTION_HEADER(Structure):
  78. _fields_ = [
  79. ('Size', c_uint24),
  80. ('Type', c_uint8)
  81. ]
  82. class FSP_COMMON_HEADER(Structure):
  83. _fields_ = [
  84. ('Signature', ARRAY(c_char, 4)),
  85. ('HeaderLength', c_uint32)
  86. ]
  87. class FSP_INFORMATION_HEADER(Structure):
  88. _fields_ = [
  89. ('Signature', ARRAY(c_char, 4)),
  90. ('HeaderLength', c_uint32),
  91. ('Reserved1', c_uint16),
  92. ('SpecVersion', c_uint8),
  93. ('HeaderRevision', c_uint8),
  94. ('ImageRevision', c_uint32),
  95. ('ImageId', ARRAY(c_char, 8)),
  96. ('ImageSize', c_uint32),
  97. ('ImageBase', c_uint32),
  98. ('ImageAttribute', c_uint16),
  99. ('ComponentAttribute', c_uint16),
  100. ('CfgRegionOffset', c_uint32),
  101. ('CfgRegionSize', c_uint32),
  102. ('Reserved2', c_uint32),
  103. ('TempRamInitEntryOffset', c_uint32),
  104. ('Reserved3', c_uint32),
  105. ('NotifyPhaseEntryOffset', c_uint32),
  106. ('FspMemoryInitEntryOffset', c_uint32),
  107. ('TempRamExitEntryOffset', c_uint32),
  108. ('FspSiliconInitEntryOffset', c_uint32),
  109. ('FspMultiPhaseSiInitEntryOffset', c_uint32),
  110. ('ExtendedImageRevision', c_uint16),
  111. ('Reserved4', c_uint16),
  112. ('FspMultiPhaseMemInitEntryOffset', c_uint32),
  113. ('FspSmmInitEntryOffset', c_uint32)
  114. ]
  115. class FSP_PATCH_TABLE(Structure):
  116. _fields_ = [
  117. ('Signature', ARRAY(c_char, 4)),
  118. ('HeaderLength', c_uint16),
  119. ('HeaderRevision', c_uint8),
  120. ('Reserved', c_uint8),
  121. ('PatchEntryNum', c_uint32)
  122. ]
  123. class EFI_IMAGE_DATA_DIRECTORY(Structure):
  124. _fields_ = [
  125. ('VirtualAddress', c_uint32),
  126. ('Size', c_uint32)
  127. ]
  128. class EFI_TE_IMAGE_HEADER(Structure):
  129. _fields_ = [
  130. ('Signature', ARRAY(c_char, 2)),
  131. ('Machine', c_uint16),
  132. ('NumberOfSections', c_uint8),
  133. ('Subsystem', c_uint8),
  134. ('StrippedSize', c_uint16),
  135. ('AddressOfEntryPoint', c_uint32),
  136. ('BaseOfCode', c_uint32),
  137. ('ImageBase', c_uint64),
  138. ('DataDirectoryBaseReloc', EFI_IMAGE_DATA_DIRECTORY),
  139. ('DataDirectoryDebug', EFI_IMAGE_DATA_DIRECTORY)
  140. ]
  141. class EFI_IMAGE_DOS_HEADER(Structure):
  142. _fields_ = [
  143. ('e_magic', c_uint16),
  144. ('e_cblp', c_uint16),
  145. ('e_cp', c_uint16),
  146. ('e_crlc', c_uint16),
  147. ('e_cparhdr', c_uint16),
  148. ('e_minalloc', c_uint16),
  149. ('e_maxalloc', c_uint16),
  150. ('e_ss', c_uint16),
  151. ('e_sp', c_uint16),
  152. ('e_csum', c_uint16),
  153. ('e_ip', c_uint16),
  154. ('e_cs', c_uint16),
  155. ('e_lfarlc', c_uint16),
  156. ('e_ovno', c_uint16),
  157. ('e_res', ARRAY(c_uint16, 4)),
  158. ('e_oemid', c_uint16),
  159. ('e_oeminfo', c_uint16),
  160. ('e_res2', ARRAY(c_uint16, 10)),
  161. ('e_lfanew', c_uint16)
  162. ]
  163. class EFI_IMAGE_FILE_HEADER(Structure):
  164. _fields_ = [
  165. ('Machine', c_uint16),
  166. ('NumberOfSections', c_uint16),
  167. ('TimeDateStamp', c_uint32),
  168. ('PointerToSymbolTable', c_uint32),
  169. ('NumberOfSymbols', c_uint32),
  170. ('SizeOfOptionalHeader', c_uint16),
  171. ('Characteristics', c_uint16)
  172. ]
  173. class PE_RELOC_BLOCK_HEADER(Structure):
  174. _fields_ = [
  175. ('PageRVA', c_uint32),
  176. ('BlockSize', c_uint32)
  177. ]
  178. class EFI_IMAGE_OPTIONAL_HEADER32(Structure):
  179. _fields_ = [
  180. ('Magic', c_uint16),
  181. ('MajorLinkerVersion', c_uint8),
  182. ('MinorLinkerVersion', c_uint8),
  183. ('SizeOfCode', c_uint32),
  184. ('SizeOfInitializedData', c_uint32),
  185. ('SizeOfUninitializedData', c_uint32),
  186. ('AddressOfEntryPoint', c_uint32),
  187. ('BaseOfCode', c_uint32),
  188. ('BaseOfData', c_uint32),
  189. ('ImageBase', c_uint32),
  190. ('SectionAlignment', c_uint32),
  191. ('FileAlignment', c_uint32),
  192. ('MajorOperatingSystemVersion', c_uint16),
  193. ('MinorOperatingSystemVersion', c_uint16),
  194. ('MajorImageVersion', c_uint16),
  195. ('MinorImageVersion', c_uint16),
  196. ('MajorSubsystemVersion', c_uint16),
  197. ('MinorSubsystemVersion', c_uint16),
  198. ('Win32VersionValue', c_uint32),
  199. ('SizeOfImage', c_uint32),
  200. ('SizeOfHeaders', c_uint32),
  201. ('CheckSum' , c_uint32),
  202. ('Subsystem', c_uint16),
  203. ('DllCharacteristics', c_uint16),
  204. ('SizeOfStackReserve', c_uint32),
  205. ('SizeOfStackCommit' , c_uint32),
  206. ('SizeOfHeapReserve', c_uint32),
  207. ('SizeOfHeapCommit' , c_uint32),
  208. ('LoaderFlags' , c_uint32),
  209. ('NumberOfRvaAndSizes', c_uint32),
  210. ('DataDirectory', ARRAY(EFI_IMAGE_DATA_DIRECTORY, 16))
  211. ]
  212. class EFI_IMAGE_OPTIONAL_HEADER32_PLUS(Structure):
  213. _fields_ = [
  214. ('Magic', c_uint16),
  215. ('MajorLinkerVersion', c_uint8),
  216. ('MinorLinkerVersion', c_uint8),
  217. ('SizeOfCode', c_uint32),
  218. ('SizeOfInitializedData', c_uint32),
  219. ('SizeOfUninitializedData', c_uint32),
  220. ('AddressOfEntryPoint', c_uint32),
  221. ('BaseOfCode', c_uint32),
  222. ('ImageBase', c_uint64),
  223. ('SectionAlignment', c_uint32),
  224. ('FileAlignment', c_uint32),
  225. ('MajorOperatingSystemVersion', c_uint16),
  226. ('MinorOperatingSystemVersion', c_uint16),
  227. ('MajorImageVersion', c_uint16),
  228. ('MinorImageVersion', c_uint16),
  229. ('MajorSubsystemVersion', c_uint16),
  230. ('MinorSubsystemVersion', c_uint16),
  231. ('Win32VersionValue', c_uint32),
  232. ('SizeOfImage', c_uint32),
  233. ('SizeOfHeaders', c_uint32),
  234. ('CheckSum' , c_uint32),
  235. ('Subsystem', c_uint16),
  236. ('DllCharacteristics', c_uint16),
  237. ('SizeOfStackReserve', c_uint64),
  238. ('SizeOfStackCommit' , c_uint64),
  239. ('SizeOfHeapReserve', c_uint64),
  240. ('SizeOfHeapCommit' , c_uint64),
  241. ('LoaderFlags' , c_uint32),
  242. ('NumberOfRvaAndSizes', c_uint32),
  243. ('DataDirectory', ARRAY(EFI_IMAGE_DATA_DIRECTORY, 16))
  244. ]
  245. class EFI_IMAGE_OPTIONAL_HEADER(Union):
  246. _fields_ = [
  247. ('PeOptHdr', EFI_IMAGE_OPTIONAL_HEADER32),
  248. ('PePlusOptHdr', EFI_IMAGE_OPTIONAL_HEADER32_PLUS)
  249. ]
  250. class EFI_IMAGE_NT_HEADERS32(Structure):
  251. _fields_ = [
  252. ('Signature', c_uint32),
  253. ('FileHeader', EFI_IMAGE_FILE_HEADER),
  254. ('OptionalHeader', EFI_IMAGE_OPTIONAL_HEADER)
  255. ]
  256. class EFI_IMAGE_DIRECTORY_ENTRY:
  257. EXPORT = 0
  258. IMPORT = 1
  259. RESOURCE = 2
  260. EXCEPTION = 3
  261. SECURITY = 4
  262. BASERELOC = 5
  263. DEBUG = 6
  264. COPYRIGHT = 7
  265. GLOBALPTR = 8
  266. TLS = 9
  267. LOAD_CONFIG = 10
  268. class EFI_FV_FILETYPE:
  269. ALL = 0x00
  270. RAW = 0x01
  271. FREEFORM = 0x02
  272. SECURITY_CORE = 0x03
  273. PEI_CORE = 0x04
  274. DXE_CORE = 0x05
  275. PEIM = 0x06
  276. DRIVER = 0x07
  277. COMBINED_PEIM_DRIVER = 0x08
  278. APPLICATION = 0x09
  279. SMM = 0x0a
  280. FIRMWARE_VOLUME_IMAGE = 0x0b
  281. COMBINED_SMM_DXE = 0x0c
  282. SMM_CORE = 0x0d
  283. OEM_MIN = 0xc0
  284. OEM_MAX = 0xdf
  285. DEBUG_MIN = 0xe0
  286. DEBUG_MAX = 0xef
  287. FFS_MIN = 0xf0
  288. FFS_MAX = 0xff
  289. FFS_PAD = 0xf0
  290. class EFI_SECTION_TYPE:
  291. """Enumeration of all valid firmware file section types."""
  292. ALL = 0x00
  293. COMPRESSION = 0x01
  294. GUID_DEFINED = 0x02
  295. DISPOSABLE = 0x03
  296. PE32 = 0x10
  297. PIC = 0x11
  298. TE = 0x12
  299. DXE_DEPEX = 0x13
  300. VERSION = 0x14
  301. USER_INTERFACE = 0x15
  302. COMPATIBILITY16 = 0x16
  303. FIRMWARE_VOLUME_IMAGE = 0x17
  304. FREEFORM_SUBTYPE_GUID = 0x18
  305. RAW = 0x19
  306. PEI_DEPEX = 0x1b
  307. SMM_DEPEX = 0x1c
  308. def AlignPtr (offset, alignment = 8):
  309. return (offset + alignment - 1) & ~(alignment - 1)
  310. def Bytes2Val (bytes):
  311. return reduce(lambda x,y: (x<<8)|y, bytes[::-1] )
  312. def Val2Bytes (value, blen):
  313. return [(value>>(i*8) & 0xff) for i in range(blen)]
  314. def IsIntegerType (val):
  315. if sys.version_info[0] < 3:
  316. if type(val) in (int, long):
  317. return True
  318. else:
  319. if type(val) is int:
  320. return True
  321. return False
  322. def IsStrType (val):
  323. if sys.version_info[0] < 3:
  324. if type(val) is str:
  325. return True
  326. else:
  327. if type(val) is bytes:
  328. return True
  329. return False
  330. def HandleNameStr (val):
  331. if sys.version_info[0] < 3:
  332. rep = "0x%X ('%s')" % (Bytes2Val (bytearray (val)), val)
  333. else:
  334. rep = "0x%X ('%s')" % (Bytes2Val (bytearray (val)), str (val, 'utf-8'))
  335. return rep
  336. def OutputStruct (obj, indent = 0, plen = 0):
  337. if indent:
  338. body = ''
  339. else:
  340. body = (' ' * indent + '<%s>:\n') % obj.__class__.__name__
  341. if plen == 0:
  342. plen = sizeof(obj)
  343. max_key_len = 26
  344. pstr = (' ' * (indent + 1) + '{0:<%d} = {1}\n') % max_key_len
  345. for field in obj._fields_:
  346. key = field[0]
  347. val = getattr(obj, key)
  348. rep = ''
  349. if not isinstance(val, c_uint24) and isinstance(val, Structure):
  350. body += pstr.format(key, val.__class__.__name__)
  351. body += OutputStruct (val, indent + 1)
  352. plen -= sizeof(val)
  353. else:
  354. if IsStrType (val):
  355. rep = HandleNameStr (val)
  356. elif IsIntegerType (val):
  357. if (key == 'ImageRevision'):
  358. FspImageRevisionMajor = ((val >> 24) & 0xFF)
  359. FspImageRevisionMinor = ((val >> 16) & 0xFF)
  360. FspImageRevisionRevision = ((val >> 8) & 0xFF)
  361. FspImageRevisionBuildNumber = (val & 0xFF)
  362. rep = '0x%08X' % val
  363. elif (key == 'ExtendedImageRevision'):
  364. FspImageRevisionRevision |= (val & 0xFF00)
  365. FspImageRevisionBuildNumber |= ((val << 8) & 0xFF00)
  366. rep = "0x%04X ('%02X.%02X.%04X.%04X')" % (val, FspImageRevisionMajor, FspImageRevisionMinor, FspImageRevisionRevision, FspImageRevisionBuildNumber)
  367. elif field[1] == c_uint64:
  368. rep = '0x%016X' % val
  369. elif field[1] == c_uint32:
  370. rep = '0x%08X' % val
  371. elif field[1] == c_uint16:
  372. rep = '0x%04X' % val
  373. elif field[1] == c_uint8:
  374. rep = '0x%02X' % val
  375. else:
  376. rep = '0x%X' % val
  377. elif isinstance(val, c_uint24):
  378. rep = '0x%X' % val.get_value()
  379. elif 'c_ubyte_Array' in str(type(val)):
  380. if sizeof(val) == 16:
  381. if sys.version_info[0] < 3:
  382. rep = str(bytearray(val))
  383. else:
  384. rep = bytes(val)
  385. rep = str(uuid.UUID(bytes_le = rep)).upper()
  386. else:
  387. res = ['0x%02X'%i for i in bytearray(val)]
  388. rep = '[%s]' % (','.join(res))
  389. else:
  390. rep = str(val)
  391. plen -= sizeof(field[1])
  392. body += pstr.format(key, rep)
  393. if plen <= 0:
  394. break
  395. return body
  396. class Section:
  397. def __init__(self, offset, secdata):
  398. self.SecHdr = EFI_COMMON_SECTION_HEADER.from_buffer (secdata, 0)
  399. self.SecData = secdata[0:int(self.SecHdr.Size)]
  400. self.Offset = offset
  401. class FirmwareFile:
  402. def __init__(self, offset, filedata):
  403. self.FfsHdr = EFI_FFS_FILE_HEADER.from_buffer (filedata, 0)
  404. self.FfsData = filedata[0:int(self.FfsHdr.Size)]
  405. self.Offset = offset
  406. self.SecList = []
  407. def ParseFfs(self):
  408. ffssize = len(self.FfsData)
  409. offset = sizeof(self.FfsHdr)
  410. if self.FfsHdr.Name != '\xff' * 16:
  411. while offset < (ffssize - sizeof (EFI_COMMON_SECTION_HEADER)):
  412. sechdr = EFI_COMMON_SECTION_HEADER.from_buffer (self.FfsData, offset)
  413. sec = Section (offset, self.FfsData[offset:offset + int(sechdr.Size)])
  414. self.SecList.append(sec)
  415. offset += int(sechdr.Size)
  416. offset = AlignPtr(offset, 4)
  417. class FirmwareVolume:
  418. def __init__(self, offset, fvdata):
  419. self.FvHdr = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (fvdata, 0)
  420. self.FvData = fvdata[0 : self.FvHdr.FvLength]
  421. self.Offset = offset
  422. if self.FvHdr.ExtHeaderOffset > 0:
  423. self.FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FvData, self.FvHdr.ExtHeaderOffset)
  424. else:
  425. self.FvExtHdr = None
  426. self.FfsList = []
  427. def ParseFv(self):
  428. fvsize = len(self.FvData)
  429. if self.FvExtHdr:
  430. offset = self.FvHdr.ExtHeaderOffset + self.FvExtHdr.ExtHeaderSize
  431. else:
  432. offset = self.FvHdr.HeaderLength
  433. offset = AlignPtr(offset)
  434. while offset < (fvsize - sizeof (EFI_FFS_FILE_HEADER)):
  435. ffshdr = EFI_FFS_FILE_HEADER.from_buffer (self.FvData, offset)
  436. if (ffshdr.Name == '\xff' * 16) and (int(ffshdr.Size) == 0xFFFFFF):
  437. offset = fvsize
  438. else:
  439. ffs = FirmwareFile (offset, self.FvData[offset:offset + int(ffshdr.Size)])
  440. ffs.ParseFfs()
  441. self.FfsList.append(ffs)
  442. offset += int(ffshdr.Size)
  443. offset = AlignPtr(offset)
  444. class FspImage:
  445. def __init__(self, offset, fih, fihoff, patch):
  446. self.Fih = fih
  447. self.FihOffset = fihoff
  448. self.Offset = offset
  449. self.FvIdxList = []
  450. self.Type = "XTMSIXXXOXXXXXXX"[(fih.ComponentAttribute >> 12) & 0x0F]
  451. self.PatchList = patch
  452. self.PatchList.append(fihoff + 0x1C)
  453. def AppendFv(self, FvIdx):
  454. self.FvIdxList.append(FvIdx)
  455. def Patch(self, delta, fdbin):
  456. count = 0
  457. applied = 0
  458. for idx, patch in enumerate(self.PatchList):
  459. ptype = (patch>>24) & 0x0F
  460. if ptype not in [0x00, 0x0F]:
  461. raise Exception('ERROR: Invalid patch type %d !' % ptype)
  462. if patch & 0x80000000:
  463. patch = self.Fih.ImageSize - (0x1000000 - (patch & 0xFFFFFF))
  464. else:
  465. patch = patch & 0xFFFFFF
  466. if (patch < self.Fih.ImageSize) and (patch + sizeof(c_uint32) <= self.Fih.ImageSize):
  467. offset = patch + self.Offset
  468. value = Bytes2Val(fdbin[offset:offset+sizeof(c_uint32)])
  469. value += delta
  470. fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))
  471. applied += 1
  472. count += 1
  473. # Don't count the FSP base address patch entry appended at the end
  474. if count != 0:
  475. count -= 1
  476. applied -= 1
  477. return (count, applied)
  478. class FirmwareDevice:
  479. def __init__(self, offset, fdfile):
  480. self.FvList = []
  481. self.FspList = []
  482. self.FdFile = fdfile
  483. self.Offset = 0
  484. hfsp = open (self.FdFile, 'rb')
  485. self.FdData = bytearray(hfsp.read())
  486. hfsp.close()
  487. def ParseFd(self):
  488. offset = 0
  489. fdsize = len(self.FdData)
  490. self.FvList = []
  491. while offset < (fdsize - sizeof (EFI_FIRMWARE_VOLUME_HEADER)):
  492. fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FdData, offset)
  493. if b'_FVH' != fvh.Signature:
  494. raise Exception("ERROR: Invalid FV header !")
  495. fv = FirmwareVolume (offset, self.FdData[offset:offset + fvh.FvLength])
  496. fv.ParseFv ()
  497. self.FvList.append(fv)
  498. offset += fv.FvHdr.FvLength
  499. def CheckFsp (self):
  500. if len(self.FspList) == 0:
  501. return
  502. fih = None
  503. for fsp in self.FspList:
  504. if not fih:
  505. fih = fsp.Fih
  506. else:
  507. newfih = fsp.Fih
  508. if (newfih.ImageId != fih.ImageId) or (newfih.ImageRevision != fih.ImageRevision):
  509. raise Exception("ERROR: Inconsistent FSP ImageId or ImageRevision detected !")
  510. def ParseFsp(self):
  511. flen = 0
  512. for idx, fv in enumerate(self.FvList):
  513. # Check if this FV contains FSP header
  514. if flen == 0:
  515. if len(fv.FfsList) == 0:
  516. continue
  517. ffs = fv.FfsList[0]
  518. if len(ffs.SecList) == 0:
  519. continue
  520. sec = ffs.SecList[0]
  521. if sec.SecHdr.Type != EFI_SECTION_TYPE.RAW:
  522. continue
  523. fihoffset = ffs.Offset + sec.Offset + sizeof(sec.SecHdr)
  524. fspoffset = fv.Offset
  525. offset = fspoffset + fihoffset
  526. fih = FSP_INFORMATION_HEADER.from_buffer (self.FdData, offset)
  527. if b'FSPH' != fih.Signature:
  528. continue
  529. offset += fih.HeaderLength
  530. offset = AlignPtr(offset, 4)
  531. plist = []
  532. while True:
  533. fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset)
  534. if b'FSPP' != fch.Signature:
  535. offset += fch.HeaderLength
  536. offset = AlignPtr(offset, 4)
  537. else:
  538. fspp = FSP_PATCH_TABLE.from_buffer (self.FdData, offset)
  539. offset += sizeof(fspp)
  540. pdata = (c_uint32 * fspp.PatchEntryNum).from_buffer(self.FdData, offset)
  541. plist = list(pdata)
  542. break
  543. fsp = FspImage (fspoffset, fih, fihoffset, plist)
  544. fsp.AppendFv (idx)
  545. self.FspList.append(fsp)
  546. flen = fsp.Fih.ImageSize - fv.FvHdr.FvLength
  547. else:
  548. fsp.AppendFv (idx)
  549. flen -= fv.FvHdr.FvLength
  550. if flen < 0:
  551. raise Exception("ERROR: Incorrect FV size in image !")
  552. self.CheckFsp ()
  553. class PeTeImage:
  554. def __init__(self, offset, data):
  555. self.Offset = offset
  556. tehdr = EFI_TE_IMAGE_HEADER.from_buffer (data, 0)
  557. if tehdr.Signature == b'VZ': # TE image
  558. self.TeHdr = tehdr
  559. elif tehdr.Signature == b'MZ': # PE image
  560. self.TeHdr = None
  561. self.DosHdr = EFI_IMAGE_DOS_HEADER.from_buffer (data, 0)
  562. self.PeHdr = EFI_IMAGE_NT_HEADERS32.from_buffer (data, self.DosHdr.e_lfanew)
  563. if self.PeHdr.Signature != 0x4550:
  564. raise Exception("ERROR: Invalid PE32 header !")
  565. if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b: # PE32 image
  566. if self.PeHdr.FileHeader.SizeOfOptionalHeader < EFI_IMAGE_OPTIONAL_HEADER32.DataDirectory.offset:
  567. raise Exception("ERROR: Unsupported PE32 image !")
  568. if self.PeHdr.OptionalHeader.PeOptHdr.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC:
  569. raise Exception("ERROR: No relocation information available !")
  570. elif self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x20b: # PE32+ image
  571. if self.PeHdr.FileHeader.SizeOfOptionalHeader < EFI_IMAGE_OPTIONAL_HEADER32_PLUS.DataDirectory.offset:
  572. raise Exception("ERROR: Unsupported PE32+ image !")
  573. if self.PeHdr.OptionalHeader.PePlusOptHdr.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC:
  574. raise Exception("ERROR: No relocation information available !")
  575. else:
  576. raise Exception("ERROR: Invalid PE32 optional header !")
  577. self.Offset = offset
  578. self.Data = data
  579. self.RelocList = []
  580. def IsTeImage(self):
  581. return self.TeHdr is not None
  582. def ParseReloc(self):
  583. if self.IsTeImage():
  584. rsize = self.TeHdr.DataDirectoryBaseReloc.Size
  585. roffset = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + self.TeHdr.DataDirectoryBaseReloc.VirtualAddress
  586. else:
  587. # Assuming PE32 image type (self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b)
  588. rsize = self.PeHdr.OptionalHeader.PeOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].Size
  589. roffset = self.PeHdr.OptionalHeader.PeOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].VirtualAddress
  590. if self.PeHdr.OptionalHeader.PePlusOptHdr.Magic == 0x20b: # PE32+ image
  591. rsize = self.PeHdr.OptionalHeader.PePlusOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].Size
  592. roffset = self.PeHdr.OptionalHeader.PePlusOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].VirtualAddress
  593. alignment = 4
  594. offset = roffset
  595. while offset < roffset + rsize:
  596. offset = AlignPtr(offset, 4)
  597. blkhdr = PE_RELOC_BLOCK_HEADER.from_buffer(self.Data, offset)
  598. offset += sizeof(blkhdr)
  599. # Read relocation type,offset pairs
  600. rlen = blkhdr.BlockSize - sizeof(PE_RELOC_BLOCK_HEADER)
  601. rnum = int (rlen/sizeof(c_uint16))
  602. rdata = (c_uint16 * rnum).from_buffer(self.Data, offset)
  603. for each in rdata:
  604. roff = each & 0xfff
  605. rtype = each >> 12
  606. if rtype == 0: # IMAGE_REL_BASED_ABSOLUTE:
  607. continue
  608. if ((rtype != 3) and (rtype != 10)): # IMAGE_REL_BASED_HIGHLOW and IMAGE_REL_BASED_DIR64
  609. raise Exception("ERROR: Unsupported relocation type %d!" % rtype)
  610. # Calculate the offset of the relocation
  611. aoff = blkhdr.PageRVA + roff
  612. if self.IsTeImage():
  613. aoff += sizeof(self.TeHdr) - self.TeHdr.StrippedSize
  614. self.RelocList.append((rtype, aoff))
  615. offset += sizeof(rdata)
  616. def Rebase(self, delta, fdbin):
  617. count = 0
  618. if delta == 0:
  619. return count
  620. for (rtype, roff) in self.RelocList:
  621. if rtype == 3: # IMAGE_REL_BASED_HIGHLOW
  622. offset = roff + self.Offset
  623. value = Bytes2Val(fdbin[offset:offset+sizeof(c_uint32)])
  624. value += delta
  625. fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))
  626. count += 1
  627. elif rtype == 10: # IMAGE_REL_BASED_DIR64
  628. offset = roff + self.Offset
  629. value = Bytes2Val(fdbin[offset:offset+sizeof(c_uint64)])
  630. value += delta
  631. fdbin[offset:offset+sizeof(c_uint64)] = Val2Bytes(value, sizeof(c_uint64))
  632. count += 1
  633. else:
  634. raise Exception('ERROR: Unknown relocation type %d !' % rtype)
  635. if self.IsTeImage():
  636. offset = self.Offset + EFI_TE_IMAGE_HEADER.ImageBase.offset
  637. size = EFI_TE_IMAGE_HEADER.ImageBase.size
  638. else:
  639. offset = self.Offset + self.DosHdr.e_lfanew
  640. offset += EFI_IMAGE_NT_HEADERS32.OptionalHeader.offset
  641. if self.PeHdr.OptionalHeader.PePlusOptHdr.Magic == 0x20b: # PE32+ image
  642. offset += EFI_IMAGE_OPTIONAL_HEADER32_PLUS.ImageBase.offset
  643. size = EFI_IMAGE_OPTIONAL_HEADER32_PLUS.ImageBase.size
  644. else:
  645. offset += EFI_IMAGE_OPTIONAL_HEADER32.ImageBase.offset
  646. size = EFI_IMAGE_OPTIONAL_HEADER32.ImageBase.size
  647. value = Bytes2Val(fdbin[offset:offset+size]) + delta
  648. fdbin[offset:offset+size] = Val2Bytes(value, size)
  649. return count
  650. def ShowFspInfo (fspfile):
  651. fd = FirmwareDevice(0, fspfile)
  652. fd.ParseFd ()
  653. fd.ParseFsp ()
  654. print ("\nFound the following %d Firmware Volumes in FSP binary:" % (len(fd.FvList)))
  655. for idx, fv in enumerate(fd.FvList):
  656. name = fv.FvExtHdr.FvName
  657. if not name:
  658. name = '\xff' * 16
  659. else:
  660. if sys.version_info[0] < 3:
  661. name = str(bytearray(name))
  662. else:
  663. name = bytes(name)
  664. guid = uuid.UUID(bytes_le = name)
  665. print ("FV%d:" % idx)
  666. print (" GUID : %s" % str(guid).upper())
  667. print (" Offset : 0x%08X" % fv.Offset)
  668. print (" Length : 0x%08X" % fv.FvHdr.FvLength)
  669. print ("\n")
  670. for fsp in fd.FspList:
  671. fvlist = map(lambda x : 'FV%d' % x, fsp.FvIdxList)
  672. print ("FSP_%s contains %s" % (fsp.Type, ','.join(fvlist)))
  673. print ("%s" % (OutputStruct(fsp.Fih, 0, fsp.Fih.HeaderLength)))
  674. def GenFspHdr (fspfile, outdir, hfile):
  675. fd = FirmwareDevice(0, fspfile)
  676. fd.ParseFd ()
  677. fd.ParseFsp ()
  678. if not hfile:
  679. hfile = os.path.splitext(os.path.basename(fspfile))[0] + '.h'
  680. fspname, ext = os.path.splitext(os.path.basename(hfile))
  681. filename = os.path.join(outdir, fspname + ext)
  682. hfsp = open(filename, 'w')
  683. hfsp.write ('%s\n\n' % CopyRightHeaderFile)
  684. firstfv = True
  685. for fsp in fd.FspList:
  686. fih = fsp.Fih
  687. if firstfv:
  688. if sys.version_info[0] < 3:
  689. hfsp.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), fih.ImageId))
  690. else:
  691. hfsp.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), str (fih.ImageId, 'utf-8')))
  692. hfsp.write("#define FSP_IMAGE_REV 0x%08X \n\n" % fih.ImageRevision)
  693. firstfv = False
  694. fv = fd.FvList[fsp.FvIdxList[0]]
  695. hfsp.write ('#define FSP%s_BASE 0x%08X\n' % (fsp.Type, fih.ImageBase))
  696. hfsp.write ('#define FSP%s_OFFSET 0x%08X\n' % (fsp.Type, fv.Offset))
  697. hfsp.write ('#define FSP%s_LENGTH 0x%08X\n\n' % (fsp.Type, fih.ImageSize))
  698. hfsp.close()
  699. def SplitFspBin (fspfile, outdir, nametemplate):
  700. fd = FirmwareDevice(0, fspfile)
  701. fd.ParseFd ()
  702. fd.ParseFsp ()
  703. for fsp in fd.FspList:
  704. if fsp.Fih.HeaderRevision < 3:
  705. raise Exception("ERROR: FSP 1.x is not supported by the split command !")
  706. ftype = fsp.Type
  707. if not nametemplate:
  708. nametemplate = fspfile
  709. fspname, ext = os.path.splitext(os.path.basename(nametemplate))
  710. filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext)
  711. hfsp = open(filename, 'wb')
  712. print ("Create FSP component file '%s'" % filename)
  713. for fvidx in fsp.FvIdxList:
  714. fv = fd.FvList[fvidx]
  715. hfsp.write(fv.FvData)
  716. hfsp.close()
  717. def RebaseFspBin (FspBinary, FspComponent, FspBase, OutputDir, OutputFile):
  718. fd = FirmwareDevice(0, FspBinary)
  719. fd.ParseFd ()
  720. fd.ParseFsp ()
  721. numcomp = len(FspComponent)
  722. baselist = FspBase
  723. if numcomp != len(baselist):
  724. print ("ERROR: Required number of base does not match number of FSP component !")
  725. return
  726. newfspbin = fd.FdData[:]
  727. for idx, fspcomp in enumerate(FspComponent):
  728. found = False
  729. for fsp in fd.FspList:
  730. # Is this FSP 1.x single binary?
  731. if fsp.Fih.HeaderRevision < 3:
  732. found = True
  733. ftype = 'X'
  734. break
  735. ftype = fsp.Type.lower()
  736. if ftype == fspcomp:
  737. found = True
  738. break
  739. if not found:
  740. print ("ERROR: Could not find FSP_%c component to rebase !" % fspcomp.upper())
  741. return
  742. fspbase = baselist[idx]
  743. if fspbase.startswith('0x'):
  744. newbase = int(fspbase, 16)
  745. else:
  746. newbase = int(fspbase)
  747. oldbase = fsp.Fih.ImageBase
  748. delta = newbase - oldbase
  749. print ("Rebase FSP-%c from 0x%08X to 0x%08X:" % (ftype.upper(),oldbase,newbase))
  750. imglist = []
  751. for fvidx in fsp.FvIdxList:
  752. fv = fd.FvList[fvidx]
  753. for ffs in fv.FfsList:
  754. for sec in ffs.SecList:
  755. if sec.SecHdr.Type in [EFI_SECTION_TYPE.TE, EFI_SECTION_TYPE.PE32]: # TE or PE32
  756. offset = fd.Offset + fv.Offset + ffs.Offset + sec.Offset + sizeof(sec.SecHdr)
  757. imglist.append ((offset, len(sec.SecData) - sizeof(sec.SecHdr)))
  758. fcount = 0
  759. pcount = 0
  760. for (offset, length) in imglist:
  761. img = PeTeImage(offset, fd.FdData[offset:offset + length])
  762. img.ParseReloc()
  763. pcount += img.Rebase(delta, newfspbin)
  764. fcount += 1
  765. print (" Patched %d entries in %d TE/PE32 images." % (pcount, fcount))
  766. (count, applied) = fsp.Patch(delta, newfspbin)
  767. print (" Patched %d entries using FSP patch table." % applied)
  768. if count != applied:
  769. print (" %d invalid entries are ignored !" % (count - applied))
  770. if OutputFile == '':
  771. filename = os.path.basename(FspBinary)
  772. base, ext = os.path.splitext(filename)
  773. OutputFile = base + "_%08X" % newbase + ext
  774. fspname, ext = os.path.splitext(os.path.basename(OutputFile))
  775. filename = os.path.join(OutputDir, fspname + ext)
  776. fd = open(filename, "wb")
  777. fd.write(newfspbin)
  778. fd.close()
  779. def main ():
  780. parser = argparse.ArgumentParser()
  781. subparsers = parser.add_subparsers(title='commands', dest="which")
  782. parser_rebase = subparsers.add_parser('rebase', help='rebase a FSP into a new base address')
  783. parser_rebase.set_defaults(which='rebase')
  784. parser_rebase.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
  785. parser_rebase.add_argument('-c', '--fspcomp', choices=['t','m','s','o','i'], nargs='+', dest='FspComponent', type=str, help='FSP component to rebase', default = "['t']", required = True)
  786. parser_rebase.add_argument('-b', '--newbase', dest='FspBase', nargs='+', type=str, help='Rebased FSP binary file name', default = '', required = True)
  787. parser_rebase.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')
  788. parser_rebase.add_argument('-n', '--outfile', dest='OutputFile', type=str, help='Rebased FSP binary file name', default = '')
  789. parser_split = subparsers.add_parser('split', help='split a FSP into multiple components')
  790. parser_split.set_defaults(which='split')
  791. parser_split.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
  792. parser_split.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')
  793. parser_split.add_argument('-n', '--nametpl', dest='NameTemplate', type=str, help='Output name template', default = '')
  794. parser_genhdr = subparsers.add_parser('genhdr', help='generate a header file for FSP binary')
  795. parser_genhdr.set_defaults(which='genhdr')
  796. parser_genhdr.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
  797. parser_genhdr.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')
  798. parser_genhdr.add_argument('-n', '--hfile', dest='HFileName', type=str, help='Output header file name', default = '')
  799. parser_info = subparsers.add_parser('info', help='display FSP information')
  800. parser_info.set_defaults(which='info')
  801. parser_info.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
  802. args = parser.parse_args()
  803. if args.which in ['rebase', 'split', 'genhdr', 'info']:
  804. if not os.path.exists(args.FspBinary):
  805. raise Exception ("ERROR: Could not locate FSP binary file '%s' !" % args.FspBinary)
  806. if hasattr(args, 'OutputDir') and not os.path.exists(args.OutputDir):
  807. raise Exception ("ERROR: Invalid output directory '%s' !" % args.OutputDir)
  808. if args.which == 'rebase':
  809. RebaseFspBin (args.FspBinary, args.FspComponent, args.FspBase, args.OutputDir, args.OutputFile)
  810. elif args.which == 'split':
  811. SplitFspBin (args.FspBinary, args.OutputDir, args.NameTemplate)
  812. elif args.which == 'genhdr':
  813. GenFspHdr (args.FspBinary, args.OutputDir, args.HFileName)
  814. elif args.which == 'info':
  815. ShowFspInfo (args.FspBinary)
  816. else:
  817. parser.print_help()
  818. return 0
  819. if __name__ == '__main__':
  820. sys.exit(main())