]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Scripts / PackageDocumentTools / plugins / EdkPlugins / basemodel / efibinary.py
1 ## @file
2 #
3 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
4 #
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
6 #
7
8 from __future__ import print_function
9 import array
10 import uuid
11 import re
12 import os
13 import logging
14 import core.pe as pe
15
16 def GetLogger():
17 return logging.getLogger('EFI Binary File')
18
19 class EFIBinaryError(Exception):
20 def __init__(self, message):
21 Exception.__init__(self)
22 self._message = message
23
24 def GetMessage(self):
25 return self._message
26
27 class EfiFd(object):
28 EFI_FV_HEADER_SIZE = 0x48
29
30 def __init__(self):
31 self._fvs = []
32
33 def Load(self, fd, size):
34 index = fd.tell()
35 while (index + self.EFI_FV_HEADER_SIZE < size):
36 fv = EfiFv(self)
37 fv.Load(fd)
38 self._fvs.append(fv)
39 index += fv.GetHeader().GetFvLength()
40 index = align(index, 8)
41 fd.seek(index)
42
43 def GetFvs(self):
44 return self._fvs
45
46 class EfiFv(object):
47 FILE_SYSTEM_GUID = uuid.UUID('{8c8ce578-8a3d-4f1c-9935-896185c32dd3}')
48
49 def __init__(self, parent=None):
50 self._size = 0
51 self._filename = None
52 self._fvheader = None
53 self._blockentries = []
54 self._ffs = []
55
56 # following field is for FV in FD
57 self._parent = parent
58 self._offset = 0
59 self._raw = array.array('B')
60
61 def Load(self, fd):
62 self._offset = fd.tell()
63 self._filename = fd.name
64
65 # get file header
66 self._fvheader = EfiFirmwareVolumeHeader.Read(fd)
67 #self._fvheader.Dump()
68
69 self._size = self._fvheader.GetFvLength()
70
71 if self._fvheader.GetFileSystemGuid() != self.FILE_SYSTEM_GUID:
72 fd.seek(self._offset)
73 self._raw.fromfile(fd, self.GetHeader().GetFvLength())
74 return
75
76 # read block map
77 blockentry = BlockMapEntry.Read(fd)
78 self._blockentries.append(blockentry)
79 while (blockentry.GetNumberBlocks() != 0 and blockentry.GetLength() != 0):
80 self._blockentries.append(blockentry)
81 blockentry = BlockMapEntry.Read(fd)
82
83
84 if self._fvheader.GetSize() + (len(self._blockentries)) * 8 != \
85 self._fvheader.GetHeaderLength():
86 raise EFIBinaryError("Volume Header length not consistent with block map!")
87
88 index = align(fd.tell(), 8)
89 count = 0
90 while ((index + EfiFfs.FFS_HEADER_SIZE) < self._size):
91 ffs = EfiFfs.Read(fd, self)
92 if not isValidGuid(ffs.GetNameGuid()):
93 break
94 self._ffs.append(ffs)
95 count += 1
96 index = align(fd.tell(), 8)
97
98 fd.seek(self._offset)
99 self._raw.fromfile(fd, self.GetHeader().GetFvLength())
100
101 def GetFfs(self):
102 return self._ffs
103
104 def GetHeader(self):
105 return self._fvheader
106
107 def GetBlockEntries(self):
108 return self._blockentries
109
110 def GetHeaderRawData(self):
111 ret = []
112 ret += self._fvheader.GetRawData()
113 for block in self._blockentries:
114 ret += block.GetRawData()
115 return ret
116
117 def GetOffset(self):
118 return 0
119
120 def GetRawData(self):
121 return self._raw.tolist()
122
123 class BinaryItem(object):
124 def __init__(self, parent=None):
125 self._size = 0
126 self._arr = array.array('B')
127 self._parent = parent
128
129 @classmethod
130 def Read(cls, fd, parent=None):
131 item = cls(parent)
132 item.fromfile(fd)
133 return item
134
135 def Load(self, fd):
136 self.fromfile(fd)
137
138 def GetSize(self):
139 """should be implemented by inherited class"""
140
141 def fromfile(self, fd):
142 self._arr.fromfile(fd, self.GetSize())
143
144 def GetParent(self):
145 return self._parent
146
147 class EfiFirmwareVolumeHeader(BinaryItem):
148 def GetSize(self):
149 return 56
150
151 def GetSigunature(self):
152 list = self._arr.tolist()
153 sig = ''
154 for x in list[40:44]:
155 sig += chr(x)
156 return sig
157
158 def GetAttribute(self):
159 return list2int(self._arr.tolist()[44:48])
160
161 def GetErasePolarity(self):
162 list = self.GetAttrStrings()
163 if 'EFI_FVB2_ERASE_POLARITY' in list:
164 return True
165 return False
166
167 def GetAttrStrings(self):
168 list = []
169 value = self.GetAttribute()
170 if (value & 0x01) != 0:
171 list.append('EFI_FVB2_READ_DISABLED_CAP')
172 if (value & 0x02) != 0:
173 list.append('EFI_FVB2_READ_ENABLED_CAP')
174 if (value & 0x04) != 0:
175 list.append('EFI_FVB2_READ_STATUS')
176 if (value & 0x08) != 0:
177 list.append('EFI_FVB2_WRITE_DISABLED_CAP')
178 if (value & 0x10) != 0:
179 list.append('EFI_FVB2_WRITE_ENABLED_CAP')
180 if (value & 0x20) != 0:
181 list.append('EFI_FVB2_WRITE_STATUS')
182 if (value & 0x40) != 0:
183 list.append('EFI_FVB2_LOCK_CAP')
184 if (value & 0x80) != 0:
185 list.append('EFI_FVB2_LOCK_STATUS')
186 if (value & 0x200) != 0:
187 list.append('EFI_FVB2_STICKY_WRITE')
188 if (value & 0x400) != 0:
189 list.append('EFI_FVB2_MEMORY_MAPPED')
190 if (value & 0x800) != 0:
191 list.append('EFI_FVB2_ERASE_POLARITY')
192 if (value & 0x1000) != 0:
193 list.append('EFI_FVB2_READ_LOCK_CAP')
194 if (value & 0x00002000) != 0:
195 list.append('EFI_FVB2_READ_LOCK_STATUS')
196 if (value & 0x00004000) != 0:
197 list.append('EFI_FVB2_WRITE_LOCK_CAP')
198 if (value & 0x00008000) != 0:
199 list.append('EFI_FVB2_WRITE_LOCK_STATUS')
200
201 if (value == 0):
202 list.append('EFI_FVB2_ALIGNMENT_1')
203 if (value & 0x001F0000) == 0x00010000:
204 list.append('EFI_FVB2_ALIGNMENT_2')
205 if (value & 0x001F0000) == 0x00020000:
206 list.append('EFI_FVB2_ALIGNMENT_4')
207 if (value & 0x001F0000) == 0x00030000:
208 list.append('EFI_FVB2_ALIGNMENT_8')
209 if (value & 0x001F0000) == 0x00040000:
210 list.append('EFI_FVB2_ALIGNMENT_16')
211 if (value & 0x001F0000) == 0x00050000:
212 list.append('EFI_FVB2_ALIGNMENT_32')
213 if (value & 0x001F0000) == 0x00060000:
214 list.append('EFI_FVB2_ALIGNMENT_64')
215 if (value & 0x001F0000) == 0x00070000:
216 list.append('EFI_FVB2_ALIGNMENT_128')
217 if (value & 0x001F0000) == 0x00080000:
218 list.append('EFI_FVB2_ALIGNMENT_256')
219 if (value & 0x001F0000) == 0x00090000:
220 list.append('EFI_FVB2_ALIGNMENT_512')
221 if (value & 0x001F0000) == 0x000A0000:
222 list.append('EFI_FVB2_ALIGNMENT_1K')
223 if (value & 0x001F0000) == 0x000B0000:
224 list.append('EFI_FVB2_ALIGNMENT_2K')
225 if (value & 0x001F0000) == 0x000C0000:
226 list.append('EFI_FVB2_ALIGNMENT_4K')
227 if (value & 0x001F0000) == 0x000D0000:
228 list.append('EFI_FVB2_ALIGNMENT_8K')
229 if (value & 0x001F0000) == 0x000E0000:
230 list.append('EFI_FVB2_ALIGNMENT_16K')
231 if (value & 0x001F0000) == 0x000F0000:
232 list.append('EFI_FVB2_ALIGNMENT_32K')
233 if (value & 0x001F0000) == 0x00100000:
234 list.append('EFI_FVB2_ALIGNMENT_64K')
235 if (value & 0x001F0000) == 0x00110000:
236 list.append('EFI_FVB2_ALIGNMENT_128K')
237 if (value & 0x001F0000) == 0x00120000:
238 list.append('EFI_FVB2_ALIGNMENT_256K')
239 if (value & 0x001F0000) == 0x00130000:
240 list.append('EFI_FVB2_ALIGNMENT_512K')
241
242 return list
243
244 def GetHeaderLength(self):
245 return list2int(self._arr.tolist()[48:50])
246
247 def Dump(self):
248 print('Signature: %s' % self.GetSigunature())
249 print('Attribute: 0x%X' % self.GetAttribute())
250 print('Header Length: 0x%X' % self.GetHeaderLength())
251 print('File system Guid: ', self.GetFileSystemGuid())
252 print('Revision: 0x%X' % self.GetRevision())
253 print('FvLength: 0x%X' % self.GetFvLength())
254
255 def GetFileSystemGuid(self):
256 list = self._arr.tolist()
257 return list2guid(list[16:32])
258
259 def GetRevision(self):
260 list = self._arr.tolist()
261 return int(list[55])
262
263 def GetFvLength(self):
264 list = self._arr.tolist()
265 return list2int(list[32:40])
266
267 def GetRawData(self):
268 return self._arr.tolist()
269
270 class BlockMapEntry(BinaryItem):
271 def GetSize(self):
272 return 8
273
274 def GetNumberBlocks(self):
275 list = self._arr.tolist()
276 return list2int(list[0:4])
277
278 def GetLength(self):
279 list = self._arr.tolist()
280 return list2int(list[4:8])
281
282 def GetRawData(self):
283 return self._arr.tolist()
284
285 def __str__(self):
286 return '[BlockEntry] Number = 0x%X, length=0x%X' % (self.GetNumberBlocks(), self.GetLength())
287
288 class EfiFfs(object):
289 FFS_HEADER_SIZE = 24
290
291 def __init__(self, parent=None):
292 self._header = None
293
294 # following field is for FFS in FV file.
295 self._parent = parent
296 self._offset = 0
297 self._sections = []
298
299 def Load(self, fd):
300 self._offset = align(fd.tell(), 8)
301
302 self._header = EfiFfsHeader.Read(fd, self)
303
304 if not isValidGuid(self.GetNameGuid()):
305 return
306
307 index = self._offset
308 fileend = self._offset + self.GetSize()
309 while (index + EfiSection.EFI_SECTION_HEADER_SIZE < fileend):
310 section = EfiSection(self)
311 section.Load(fd)
312 if section.GetSize() == 0 and section.GetHeader().GetType() == 0:
313 break
314 self._sections.append(section)
315 index = fd.tell()
316
317 # rebase file pointer to next ffs file
318 index = self._offset + self._header.GetFfsSize()
319 index = align(index, 8)
320 fd.seek(index)
321
322 def GetOffset(self):
323 return self._offset
324
325 def GetSize(self):
326 return self._header.GetFfsSize()
327
328 @classmethod
329 def Read(cls, fd, parent=None):
330 item = cls(parent)
331 item.Load(fd)
332 return item
333
334 def GetNameGuid(self):
335 return self._header.GetNameGuid()
336
337 def DumpContent(self):
338 list = self._content.tolist()
339 line = []
340 count = 0
341 for item in list:
342 if count < 32:
343 line.append('0x%X' % int(item))
344 count += 1
345 else:
346 print(' '.join(line))
347 count = 0
348 line = []
349 line.append('0x%X' % int(item))
350 count += 1
351
352 def GetHeader(self):
353 return self._header
354
355 def GetParent(self):
356 return self._parent
357
358 def GetSections(self):
359 return self._sections
360
361 class EfiFfsHeader(BinaryItem):
362 ffs_state_map = {0x01:'EFI_FILE_HEADER_CONSTRUCTION',
363 0x02:'EFI_FILE_HEADER_VALID',
364 0x04:'EFI_FILE_DATA_VALID',
365 0x08:'EFI_FILE_MARKED_FOR_UPDATE',
366 0x10:'EFI_FILE_DELETED',
367 0x20:'EFI_FILE_HEADER_INVALID'}
368
369 def GetSize(self):
370 return 24
371
372 def GetNameGuid(self):
373 list = self._arr.tolist()
374 return list2guid(list[0:16])
375
376 def GetType(self):
377 list = self._arr.tolist()
378 return int(list[18])
379
380
381 def GetTypeString(self):
382 value = self.GetType()
383 if value == 0x01:
384 return 'EFI_FV_FILETYPE_RAW'
385 if value == 0x02:
386 return 'EFI_FV_FILETYPE_FREEFORM'
387 if value == 0x03:
388 return 'EFI_FV_FILETYPE_SECURITY_CORE'
389 if value == 0x04:
390 return 'EFI_FV_FILETYPE_PEI_CORE'
391 if value == 0x05:
392 return 'EFI_FV_FILETYPE_DXE_CORE'
393 if value == 0x06:
394 return 'EFI_FV_FILETYPE_PEIM'
395 if value == 0x07:
396 return 'EFI_FV_FILETYPE_DRIVER'
397 if value == 0x08:
398 return 'EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER'
399 if value == 0x09:
400 return 'EFI_FV_FILETYPE_APPLICATION'
401 if value == 0x0B:
402 return 'EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE'
403 if value == 0xc0:
404 return 'EFI_FV_FILETYPE_OEM_MIN'
405 if value == 0xdf:
406 return 'EFI_FV_FILETYPE_OEM_MAX'
407 if value == 0xe0:
408 return 'EFI_FV_FILETYPE_DEBUG_MIN'
409 if value == 0xef:
410 return 'EFI_FV_FILETYPE_DEBUG_MAX'
411 if value == 0xf0:
412 return 'EFI_FV_FILETYPE_FFS_PAD'
413 if value == 0xff:
414 return 'EFI_FV_FILETYPE_FFS_MAX'
415 return 'Unknown FFS Type'
416
417 def GetAttributes(self):
418 list = self._arr.tolist()
419 return int(list[19])
420
421 def GetFfsSize(self):
422 list = self._arr.tolist()
423 return list2int(list[20:23])
424
425 def GetState(self):
426 list = self._arr.tolist()
427 state = int(list[23])
428 polarity = self.GetParent().GetParent().GetHeader().GetErasePolarity()
429 if polarity:
430 state = (~state) & 0xFF
431 HighestBit = 0x80
432 while (HighestBit != 0) and (HighestBit & state) == 0:
433 HighestBit = HighestBit >> 1
434 return HighestBit
435
436 def GetStateString(self):
437 state = self.GetState()
438 if state in self.ffs_state_map.keys():
439 return self.ffs_state_map[state]
440 return 'Unknown Ffs State'
441
442 def Dump(self):
443 print("FFS name: ", self.GetNameGuid())
444 print("FFS type: ", self.GetType())
445 print("FFS attr: 0x%X" % self.GetAttributes())
446 print("FFS size: 0x%X" % self.GetFfsSize())
447 print("FFS state: 0x%X" % self.GetState())
448
449 def GetRawData(self):
450 return self._arr.tolist()
451
452
453 class EfiSection(object):
454 EFI_SECTION_HEADER_SIZE = 4
455
456 def __init__(self, parent=None):
457 self._size = 0
458 self._parent = parent
459 self._offset = 0
460 self._contents = array.array('B')
461
462 def Load(self, fd):
463 self._offset = align(fd.tell(), 4)
464
465 self._header = EfiSectionHeader.Read(fd, self)
466
467 if self._header.GetTypeString() == "EFI_SECTION_PE32":
468 pefile = pe.PEFile(self)
469 pefile.Load(fd, self.GetContentSize())
470
471 fd.seek(self._offset)
472 self._contents.fromfile(fd, self.GetContentSize())
473
474 # rebase file pointer to next section
475 index = self._offset + self.GetSize()
476 index = align(index, 4)
477 fd.seek(index)
478
479 def GetContentSize(self):
480 return self.GetSize() - self.EFI_SECTION_HEADER_SIZE
481
482 def GetContent(self):
483 return self._contents.tolist()
484
485 def GetSize(self):
486 return self._header.GetSectionSize()
487
488 def GetHeader(self):
489 return self._header
490
491 def GetSectionOffset(self):
492 return self._offset + self.EFI_SECTION_HEADER_SIZE
493
494 class EfiSectionHeader(BinaryItem):
495 section_type_map = {0x01: 'EFI_SECTION_COMPRESSION',
496 0x02: 'EFI_SECTION_GUID_DEFINED',
497 0x10: 'EFI_SECTION_PE32',
498 0x11: 'EFI_SECTION_PIC',
499 0x12: 'EFI_SECTION_TE',
500 0x13: 'EFI_SECTION_DXE_DEPEX',
501 0x14: 'EFI_SECTION_VERSION',
502 0x15: 'EFI_SECTION_USER_INTERFACE',
503 0x16: 'EFI_SECTION_COMPATIBILITY16',
504 0x17: 'EFI_SECTION_FIRMWARE_VOLUME_IMAGE',
505 0x18: 'EFI_SECTION_FREEFORM_SUBTYPE_GUID',
506 0x19: 'EFI_SECTION_RAW',
507 0x1B: 'EFI_SECTION_PEI_DEPEX'}
508 def GetSize(self):
509 return 4
510
511 def GetSectionSize(self):
512 list = self._arr.tolist()
513 return list2int(list[0:3])
514
515 def GetType(self):
516 list = self._arr.tolist()
517 return int(list[3])
518
519 def GetTypeString(self):
520 type = self.GetType()
521 if type not in self.section_type_map.keys():
522 return 'Unknown Section Type'
523 return self.section_type_map[type]
524
525 def Dump(self):
526 print('size = 0x%X' % self.GetSectionSize())
527 print('type = 0x%X' % self.GetType())
528
529
530
531 rMapEntry = re.compile('^(\w+)[ \(\w\)]* \(BaseAddress=([0-9a-fA-F]+), EntryPoint=([0-9a-fA-F]+), GUID=([0-9a-fA-F\-]+)')
532 class EfiFvMapFile(object):
533 def __init__(self):
534 self._mapentries = {}
535
536 def Load(self, path):
537 if not os.path.exists(path):
538 return False
539
540 try:
541 file = open(path, 'r')
542 lines = file.readlines()
543 file.close()
544 except:
545 return False
546
547 for line in lines:
548 if line[0] != ' ':
549 # new entry
550 ret = rMapEntry.match(line)
551 if ret is not None:
552 name = ret.groups()[0]
553 baseaddr = int(ret.groups()[1], 16)
554 entry = int(ret.groups()[2], 16)
555 guidstr = '{' + ret.groups()[3] + '}'
556 guid = uuid.UUID(guidstr)
557 self._mapentries[guid] = EfiFvMapFileEntry(name, baseaddr, entry, guid)
558 return True
559
560 def GetEntry(self, guid):
561 if guid in self._mapentries.keys():
562 return self._mapentries[guid]
563 return None
564
565 class EfiFvMapFileEntry(object):
566 def __init__(self, name, baseaddr, entry, guid):
567 self._name = name
568 self._baseaddr = baseaddr
569 self._entry = entry
570 self._guid = guid
571
572 def GetName(self):
573 return self._name
574
575 def GetBaseAddress(self):
576 return self._baseaddr
577
578 def GetEntryPoint(self):
579 return self._entry
580
581 def list2guid(list):
582 val1 = list2int(list[0:4])
583 val2 = list2int(list[4:6])
584 val3 = list2int(list[6:8])
585 val4 = 0
586 for item in list[8:16]:
587 val4 = (val4 << 8) | int(item)
588
589 val = val1 << 12 * 8 | val2 << 10 * 8 | val3 << 8 * 8 | val4
590 guid = uuid.UUID(int=val)
591 return guid
592
593 def list2int(list):
594 val = 0
595 for index in range(len(list) - 1, -1, -1):
596 val = (val << 8) | int(list[index])
597 return val
598
599 def align(value, alignment):
600 return (value + ((alignment - value) & (alignment - 1)))
601
602 gInvalidGuid = uuid.UUID(int=0xffffffffffffffffffffffffffffffff)
603 def isValidGuid(guid):
604 if guid == gInvalidGuid:
605 return False
606 return True