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