]>
Commit | Line | Data |
---|---|---|
a64b9449 CC |
1 | ## @file\r |
2 | # This file is used to the implementation of Bios layout handler.\r | |
3 | #\r | |
4 | # Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR>\r | |
5 | # SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
6 | ##\r | |
7 | import os\r | |
8 | from core.BiosTree import *\r | |
9 | from core.GuidTools import GUIDTools\r | |
10 | from core.BiosTreeNode import *\r | |
11 | from FirmwareStorageFormat.Common import *\r | |
12 | from utils.FmmtLogger import FmmtLogger as logger\r | |
13 | \r | |
14 | EFI_FVB2_ERASE_POLARITY = 0x00000800\r | |
15 | \r | |
16 | def ChangeSize(TargetTree, size_delta: int=0) -> None:\r | |
17 | # If Size increase delta, then should be: size_delta = -delta\r | |
18 | if type(TargetTree.Data.Header) == type(EFI_FFS_FILE_HEADER2()) or type(TargetTree.Data.Header) == type(EFI_COMMON_SECTION_HEADER2()):\r | |
19 | TargetTree.Data.Size -= size_delta\r | |
20 | TargetTree.Data.Header.ExtendedSize -= size_delta\r | |
21 | elif TargetTree.type == SECTION_TREE and TargetTree.Data.OriData:\r | |
22 | OriSize = TargetTree.Data.Header.SECTION_SIZE\r | |
23 | OriSize -= size_delta\r | |
24 | TargetTree.Data.Header.Size[0] = OriSize % (16**2)\r | |
25 | TargetTree.Data.Header.Size[1] = OriSize % (16**4) //(16**2)\r | |
26 | TargetTree.Data.Header.Size[2] = OriSize // (16**4)\r | |
27 | else:\r | |
28 | TargetTree.Data.Size -= size_delta\r | |
29 | TargetTree.Data.Header.Size[0] = TargetTree.Data.Size % (16**2)\r | |
30 | TargetTree.Data.Header.Size[1] = TargetTree.Data.Size % (16**4) //(16**2)\r | |
31 | TargetTree.Data.Header.Size[2] = TargetTree.Data.Size // (16**4)\r | |
32 | \r | |
33 | def ModifyFfsType(TargetFfs) -> None:\r | |
34 | if type(TargetFfs.Data.Header) == type(EFI_FFS_FILE_HEADER()) and TargetFfs.Data.Size > 0xFFFFFF:\r | |
35 | ExtendSize = TargetFfs.Data.Header.FFS_FILE_SIZE + 8\r | |
36 | New_Header = EFI_FFS_FILE_HEADER2()\r | |
37 | New_Header.Name = TargetFfs.Data.Header.Name\r | |
38 | New_Header.IntegrityCheck = TargetFfs.Data.Header.IntegrityCheck\r | |
39 | New_Header.Type = TargetFfs.Data.Header.Type\r | |
40 | New_Header.Attributes = TargetFfs.Data.Header.Attributes | 0x01 # set the Attribute with FFS_ATTRIB_LARGE_FILE (0x01)\r | |
41 | NewSize = 0\r | |
42 | New_Header.Size[0] = NewSize % (16**2) # minus the delta size of Header\r | |
43 | New_Header.Size[1] = NewSize % (16**4) //(16**2)\r | |
44 | New_Header.Size[2] = NewSize // (16**4)\r | |
45 | New_Header.State = TargetFfs.Data.Header.State\r | |
46 | New_Header.ExtendedSize = ExtendSize\r | |
47 | TargetFfs.Data.Header = New_Header\r | |
48 | TargetFfs.Data.Size = TargetFfs.Data.Header.FFS_FILE_SIZE\r | |
49 | TargetFfs.Data.HeaderLength = TargetFfs.Data.Header.HeaderLength\r | |
50 | TargetFfs.Data.ModCheckSum()\r | |
51 | elif type(TargetFfs.Data.Header) == type(EFI_FFS_FILE_HEADER2()) and TargetFfs.Data.Size <= 0xFFFFFF:\r | |
52 | New_Header = EFI_FFS_FILE_HEADER()\r | |
53 | New_Header.Name = TargetFfs.Data.Header.Name\r | |
54 | New_Header.IntegrityCheck = TargetFfs.Data.Header.IntegrityCheck\r | |
55 | New_Header.Type = TargetFfs.Data.Header.Type\r | |
56 | New_Header.Attributes = TargetFfs.Data.Header.Attributes - 1 # remove the FFS_ATTRIB_LARGE_FILE (0x01) from Attribute\r | |
57 | New_Header.Size[0] = (TargetFfs.Data.Size - 8) % (16**2) # minus the delta size of Header\r | |
58 | New_Header.Size[1] = (TargetFfs.Data.Size - 8) % (16**4) //(16**2)\r | |
59 | New_Header.Size[2] = (TargetFfs.Data.Size - 8) // (16**4)\r | |
60 | New_Header.State = TargetFfs.Data.Header.State\r | |
61 | TargetFfs.Data.Header = New_Header\r | |
62 | TargetFfs.Data.Size = TargetFfs.Data.Header.FFS_FILE_SIZE\r | |
63 | TargetFfs.Data.HeaderLength = TargetFfs.Data.Header.HeaderLength\r | |
64 | TargetFfs.Data.ModCheckSum()\r | |
65 | if struct2stream(TargetFfs.Parent.Data.Header.FileSystemGuid) == EFI_FIRMWARE_FILE_SYSTEM3_GUID_BYTE:\r | |
66 | NeedChange = True\r | |
67 | for item in TargetFfs.Parent.Child:\r | |
68 | if type(item.Data.Header) == type(EFI_FFS_FILE_HEADER2()):\r | |
69 | NeedChange = False\r | |
70 | if NeedChange:\r | |
71 | TargetFfs.Parent.Data.Header.FileSystemGuid = ModifyGuidFormat("8c8ce578-8a3d-4f1c-9935-896185c32dd3")\r | |
72 | \r | |
73 | if type(TargetFfs.Data.Header) == type(EFI_FFS_FILE_HEADER2()):\r | |
74 | TarParent = TargetFfs.Parent\r | |
75 | while TarParent:\r | |
76 | if TarParent.type == FV_TREE and struct2stream(TarParent.Data.Header.FileSystemGuid) == EFI_FIRMWARE_FILE_SYSTEM2_GUID_BYTE:\r | |
77 | TarParent.Data.Header.FileSystemGuid = ModifyGuidFormat("5473C07A-3DCB-4dca-BD6F-1E9689E7349A")\r | |
78 | TarParent = TarParent.Parent\r | |
79 | \r | |
80 | def PadSectionModify(PadSection, Offset) -> None:\r | |
81 | # Offset > 0, Size decrease; Offset < 0, Size increase;\r | |
82 | ChangeSize(PadSection, Offset)\r | |
83 | PadSection.Data.Data = (PadSection.Data.Size - PadSection.Data.HeaderLength) * b'\xff'\r | |
84 | \r | |
85 | def ModifySectionType(TargetSection) -> None:\r | |
86 | # If Section Size is increased larger than 0xFFFFFF, need modify Section Header from EFI_COMMON_SECTION_HEADER to EFI_COMMON_SECTION_HEADER2.\r | |
87 | if type(TargetSection.Data.Header) == type(EFI_COMMON_SECTION_HEADER()) and TargetSection.Data.Size >= 0xFFFFFF:\r | |
88 | New_Header = EFI_COMMON_SECTION_HEADER2()\r | |
89 | New_Header.Type = TargetSection.Data.Header.Type\r | |
90 | NewSize = 0xFFFFFF\r | |
91 | New_Header.Size[0] = NewSize % (16**2) # minus the delta size of Header\r | |
92 | New_Header.Size[1] = NewSize % (16**4) //(16**2)\r | |
93 | New_Header.Size[2] = NewSize // (16**4)\r | |
94 | New_Header.ExtendedSize = TargetSection.Data.Size + 4\r | |
95 | TargetSection.Data.Header = New_Header\r | |
96 | TargetSection.Data.Size = TargetSection.Data.Header.SECTION_SIZE\r | |
97 | # Align the Header's added 4 bit to 8-alignment to promise the following Ffs's align correctly.\r | |
98 | if TargetSection.LastRel.Data.IsPadSection:\r | |
99 | PadSectionModify(TargetSection.LastRel, -4)\r | |
100 | else:\r | |
101 | SecParent = TargetSection.Parent\r | |
102 | Target_index = SecParent.Child.index(TargetSection)\r | |
103 | NewPadSection = SectionNode(b'\x00\x00\x00\x19')\r | |
104 | SecParent.insertChild(NewPadSection, Target_index)\r | |
105 | # If Section Size is decreased smaller than 0xFFFFFF, need modify Section Header from EFI_COMMON_SECTION_HEADER2 to EFI_COMMON_SECTION_HEADER.\r | |
106 | elif type(TargetSection.Data.Header) == type(EFI_COMMON_SECTION_HEADER2()) and TargetSection.Data.Size < 0xFFFFFF:\r | |
107 | New_Header = EFI_COMMON_SECTION_HEADER()\r | |
108 | New_Header.Type = TargetSection.Data.Header.Type\r | |
109 | New_Header.Size[0] = (TargetSection.Data.Size - 4) % (16**2) # minus the delta size of Header\r | |
110 | New_Header.Size[1] = (TargetSection.Data.Size - 4) % (16**4) //(16**2)\r | |
111 | New_Header.Size[2] = (TargetSection.Data.Size - 4) // (16**4)\r | |
112 | TargetSection.Data.Header = New_Header\r | |
113 | TargetSection.Data.Size = TargetSection.Data.Header.SECTION_SIZE\r | |
114 | # Align the Header's added 4 bit to 8-alignment to promise the following Ffs's align correctly.\r | |
115 | if TargetSection.LastRel.Data.IsPadSection:\r | |
116 | PadSectionModify(TargetSection.LastRel, -4)\r | |
117 | else:\r | |
118 | SecParent = TargetSection.Parent\r | |
119 | Target_index = SecParent.Child.index(TargetSection)\r | |
120 | NewPadSection = SectionNode(b'\x00\x00\x00\x19')\r | |
121 | SecParent.insertChild(NewPadSection, Target_index)\r | |
122 | \r | |
123 | def ModifyFvExtData(TreeNode) -> None:\r | |
124 | FvExtData = b''\r | |
125 | if TreeNode.Data.Header.ExtHeaderOffset:\r | |
126 | FvExtHeader = struct2stream(TreeNode.Data.ExtHeader)\r | |
127 | FvExtData += FvExtHeader\r | |
128 | if TreeNode.Data.Header.ExtHeaderOffset and TreeNode.Data.ExtEntryExist:\r | |
129 | FvExtEntry = struct2stream(TreeNode.Data.ExtEntry)\r | |
130 | FvExtData += FvExtEntry\r | |
131 | if FvExtData:\r | |
132 | InfoNode = TreeNode.Child[0]\r | |
133 | InfoNode.Data.Data = FvExtData + InfoNode.Data.Data[TreeNode.Data.ExtHeader.ExtHeaderSize:]\r | |
134 | InfoNode.Data.ModCheckSum()\r | |
135 | \r | |
136 | def ModifyFvSystemGuid(TargetFv) -> None:\r | |
137 | if struct2stream(TargetFv.Data.Header.FileSystemGuid) == EFI_FIRMWARE_FILE_SYSTEM2_GUID_BYTE:\r | |
138 | TargetFv.Data.Header.FileSystemGuid = ModifyGuidFormat("5473C07A-3DCB-4dca-BD6F-1E9689E7349A")\r | |
139 | TargetFv.Data.ModCheckSum()\r | |
140 | TargetFv.Data.Data = b''\r | |
141 | for item in TargetFv.Child:\r | |
142 | if item.type == FFS_FREE_SPACE:\r | |
143 | TargetFv.Data.Data += item.Data.Data + item.Data.PadData\r | |
144 | else:\r | |
145 | TargetFv.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData\r | |
146 | \r | |
147 | class FvHandler:\r | |
148 | def __init__(self, NewFfs, TargetFfs) -> None:\r | |
149 | self.NewFfs = NewFfs\r | |
150 | self.TargetFfs = TargetFfs\r | |
151 | self.Status = False\r | |
152 | self.Remain_New_Free_Space = 0\r | |
153 | \r | |
154 | ## Use for Compress the Section Data\r | |
155 | def CompressData(self, TargetTree) -> None:\r | |
156 | TreePath = TargetTree.GetTreePath()\r | |
157 | pos = len(TreePath)\r | |
158 | self.Status = False\r | |
159 | while pos:\r | |
160 | if not self.Status:\r | |
161 | if TreePath[pos-1].type == SECTION_TREE and TreePath[pos-1].Data.Type == 0x02:\r | |
162 | self.CompressSectionData(TreePath[pos-1], None, TreePath[pos-1].Data.ExtHeader.SectionDefinitionGuid)\r | |
163 | else:\r | |
164 | if pos == len(TreePath):\r | |
165 | self.CompressSectionData(TreePath[pos-1], pos)\r | |
166 | else:\r | |
167 | self.CompressSectionData(TreePath[pos-1], None)\r | |
168 | pos -= 1\r | |
169 | \r | |
170 | def CompressSectionData(self, TargetTree, pos: int, GuidTool=None) -> None:\r | |
171 | NewData = b''\r | |
172 | temp_save_child = TargetTree.Child\r | |
173 | if TargetTree.Data:\r | |
174 | # Update current node data as adding all the header and data of its child node.\r | |
175 | for item in temp_save_child:\r | |
176 | if item.type == SECTION_TREE and not item.Data.OriData and item.Data.ExtHeader:\r | |
177 | NewData += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.Data + item.Data.PadData\r | |
178 | elif item.type == SECTION_TREE and item.Data.OriData and not item.Data.ExtHeader:\r | |
179 | NewData += struct2stream(item.Data.Header) + item.Data.OriData + item.Data.PadData\r | |
180 | elif item.type == SECTION_TREE and item.Data.OriData and item.Data.ExtHeader:\r | |
181 | NewData += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.OriData + item.Data.PadData\r | |
182 | elif item.type == FFS_FREE_SPACE:\r | |
183 | NewData += item.Data.Data + item.Data.PadData\r | |
184 | else:\r | |
185 | NewData += struct2stream(item.Data.Header) + item.Data.Data + item.Data.PadData\r | |
186 | # If node is FFS_TREE, update Pad data and Header info.\r | |
187 | # Remain_New_Free_Space is used for move more free space into lst level Fv.\r | |
188 | if TargetTree.type == FFS_TREE:\r | |
189 | New_Pad_Size = GetPadSize(len(NewData), 8)\r | |
190 | Size_delta = len(NewData) - len(TargetTree.Data.Data)\r | |
191 | ChangeSize(TargetTree, -Size_delta)\r | |
192 | Delta_Pad_Size = len(TargetTree.Data.PadData) - New_Pad_Size\r | |
193 | self.Remain_New_Free_Space += Delta_Pad_Size\r | |
194 | TargetTree.Data.PadData = b'\xff' * New_Pad_Size\r | |
195 | TargetTree.Data.ModCheckSum()\r | |
196 | # If node is FV_TREE, update Pad data and Header info.\r | |
197 | # Consume Remain_New_Free_Space is used for move more free space into lst level Fv.\r | |
198 | elif TargetTree.type == FV_TREE or TargetTree.type == SEC_FV_TREE and not pos:\r | |
199 | if self.Remain_New_Free_Space:\r | |
200 | if TargetTree.Data.Free_Space:\r | |
201 | TargetTree.Data.Free_Space += self.Remain_New_Free_Space\r | |
202 | NewData += self.Remain_New_Free_Space * b'\xff'\r | |
203 | TargetTree.Child[-1].Data.Data += self.Remain_New_Free_Space * b'\xff'\r | |
204 | else:\r | |
205 | TargetTree.Data.Data += self.Remain_New_Free_Space * b'\xff'\r | |
206 | New_Free_Space = BIOSTREE('FREE_SPACE')\r | |
207 | New_Free_Space.type = FFS_FREE_SPACE\r | |
208 | New_Free_Space.Data = FreeSpaceNode(b'\xff' * self.Remain_New_Free_Space)\r | |
209 | TargetTree.insertChild(New_Free_Space)\r | |
210 | self.Remain_New_Free_Space = 0\r | |
211 | if TargetTree.type == SEC_FV_TREE:\r | |
212 | Size_delta = len(NewData) + self.Remain_New_Free_Space - len(TargetTree.Data.Data)\r | |
213 | TargetTree.Data.Header.FvLength += Size_delta\r | |
214 | TargetTree.Data.ModFvExt()\r | |
215 | TargetTree.Data.ModFvSize()\r | |
216 | TargetTree.Data.ModExtHeaderData()\r | |
217 | ModifyFvExtData(TargetTree)\r | |
218 | TargetTree.Data.ModCheckSum()\r | |
219 | # If node is SECTION_TREE and not guided section, update Pad data and Header info.\r | |
220 | # Remain_New_Free_Space is used for move more free space into lst level Fv.\r | |
221 | elif TargetTree.type == SECTION_TREE and TargetTree.Data.Type != 0x02:\r | |
222 | New_Pad_Size = GetPadSize(len(NewData), 4)\r | |
223 | Size_delta = len(NewData) - len(TargetTree.Data.Data)\r | |
224 | ChangeSize(TargetTree, -Size_delta)\r | |
225 | if TargetTree.NextRel:\r | |
226 | Delta_Pad_Size = len(TargetTree.Data.PadData) - New_Pad_Size\r | |
227 | self.Remain_New_Free_Space += Delta_Pad_Size\r | |
228 | TargetTree.Data.PadData = b'\x00' * New_Pad_Size\r | |
229 | TargetTree.Data.Data = NewData\r | |
230 | if GuidTool:\r | |
231 | guidtool = GUIDTools().__getitem__(struct2stream(GuidTool))\r | |
232 | if not guidtool.ifexist:\r | |
233 | logger.error("GuidTool {} is not found when decompressing {} file.\n".format(guidtool.command, TargetTree.Parent.Data.Name))\r | |
234 | raise Exception("Process Failed: GuidTool not found!")\r | |
235 | CompressedData = guidtool.pack(TargetTree.Data.Data)\r | |
236 | if len(CompressedData) < len(TargetTree.Data.OriData):\r | |
237 | New_Pad_Size = GetPadSize(len(CompressedData), SECTION_COMMON_ALIGNMENT)\r | |
238 | Size_delta = len(CompressedData) - len(TargetTree.Data.OriData)\r | |
239 | ChangeSize(TargetTree, -Size_delta)\r | |
240 | if TargetTree.NextRel:\r | |
241 | TargetTree.Data.PadData = b'\x00' * New_Pad_Size\r | |
242 | self.Remain_New_Free_Space = len(TargetTree.Data.OriData) + len(TargetTree.Data.PadData) - len(CompressedData) - New_Pad_Size\r | |
243 | else:\r | |
244 | TargetTree.Data.PadData = b''\r | |
245 | self.Remain_New_Free_Space = len(TargetTree.Data.OriData) - len(CompressedData)\r | |
246 | TargetTree.Data.OriData = CompressedData\r | |
247 | elif len(CompressedData) == len(TargetTree.Data.OriData):\r | |
248 | TargetTree.Data.OriData = CompressedData\r | |
249 | elif len(CompressedData) > len(TargetTree.Data.OriData):\r | |
250 | New_Pad_Size = GetPadSize(len(CompressedData), SECTION_COMMON_ALIGNMENT)\r | |
251 | self.Remain_New_Free_Space = len(CompressedData) + New_Pad_Size - len(TargetTree.Data.OriData) - len(TargetTree.Data.PadData)\r | |
252 | self.ModifyTest(TargetTree, self.Remain_New_Free_Space)\r | |
253 | self.Status = True\r | |
254 | \r | |
255 | def ModifyTest(self, ParTree, Needed_Space: int) -> None:\r | |
256 | # If have needed space, will find if there have free space in parent tree, meanwhile update the node data.\r | |
257 | if Needed_Space > 0:\r | |
258 | # If current node is a Fv node\r | |
259 | if ParTree.type == FV_TREE or ParTree.type == SEC_FV_TREE:\r | |
260 | ParTree.Data.Data = b''\r | |
261 | # First check if Fv free space is enough for needed space.\r | |
262 | # If so, use the current Fv free space;\r | |
263 | # Else, use all the Free space, and recalculate needed space, continue finding in its parent node.\r | |
264 | Needed_Space = Needed_Space - ParTree.Data.Free_Space\r | |
265 | if Needed_Space < 0:\r | |
266 | ParTree.Child[-1].Data.Data = b'\xff' * (-Needed_Space)\r | |
267 | ParTree.Data.Free_Space = (-Needed_Space)\r | |
268 | self.Status = True\r | |
269 | else:\r | |
270 | if ParTree.type == FV_TREE:\r | |
271 | self.Status = False\r | |
272 | else:\r | |
273 | BlockSize = ParTree.Data.Header.BlockMap[0].Length\r | |
274 | New_Add_Len = BlockSize - Needed_Space%BlockSize\r | |
275 | if New_Add_Len % BlockSize:\r | |
276 | ParTree.Child[-1].Data.Data = b'\xff' * New_Add_Len\r | |
277 | ParTree.Data.Free_Space = New_Add_Len\r | |
278 | Needed_Space += New_Add_Len\r | |
279 | else:\r | |
280 | ParTree.Child.remove(ParTree.Child[-1])\r | |
281 | ParTree.Data.Free_Space = 0\r | |
282 | ParTree.Data.Size += Needed_Space\r | |
283 | ParTree.Data.Header.Fvlength = ParTree.Data.Size\r | |
284 | ModifyFvSystemGuid(ParTree)\r | |
285 | for item in ParTree.Child:\r | |
286 | if item.type == FFS_FREE_SPACE:\r | |
287 | ParTree.Data.Data += item.Data.Data + item.Data.PadData\r | |
288 | else:\r | |
289 | ParTree.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData\r | |
290 | ParTree.Data.ModFvExt()\r | |
291 | ParTree.Data.ModFvSize()\r | |
292 | ParTree.Data.ModExtHeaderData()\r | |
293 | ModifyFvExtData(ParTree)\r | |
294 | ParTree.Data.ModCheckSum()\r | |
295 | # If current node is a Ffs node\r | |
296 | elif ParTree.type == FFS_TREE:\r | |
297 | ParTree.Data.Data = b''\r | |
298 | OriHeaderLen = ParTree.Data.HeaderLength\r | |
299 | # Update its data as adding all the header and data of its child node.\r | |
300 | for item in ParTree.Child:\r | |
301 | if item.Data.OriData:\r | |
302 | if item.Data.ExtHeader:\r | |
303 | ParTree.Data.Data += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.OriData + item.Data.PadData\r | |
304 | else:\r | |
305 | ParTree.Data.Data += struct2stream(item.Data.Header)+ item.Data.OriData + item.Data.PadData\r | |
306 | else:\r | |
307 | if item.Data.ExtHeader:\r | |
308 | ParTree.Data.Data += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.Data + item.Data.PadData\r | |
309 | else:\r | |
310 | ParTree.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData\r | |
311 | ChangeSize(ParTree, -Needed_Space)\r | |
312 | ModifyFfsType(ParTree)\r | |
313 | # Recalculate pad data, update needed space with Delta_Pad_Size.\r | |
314 | Needed_Space += ParTree.Data.HeaderLength - OriHeaderLen\r | |
315 | New_Pad_Size = GetPadSize(ParTree.Data.Size, FFS_COMMON_ALIGNMENT)\r | |
316 | Delta_Pad_Size = New_Pad_Size - len(ParTree.Data.PadData)\r | |
317 | Needed_Space += Delta_Pad_Size\r | |
318 | ParTree.Data.PadData = b'\xff' * GetPadSize(ParTree.Data.Size, FFS_COMMON_ALIGNMENT)\r | |
319 | ParTree.Data.ModCheckSum()\r | |
320 | # If current node is a Section node\r | |
321 | elif ParTree.type == SECTION_TREE:\r | |
322 | OriData = ParTree.Data.Data\r | |
323 | OriHeaderLen = ParTree.Data.HeaderLength\r | |
324 | ParTree.Data.Data = b''\r | |
325 | # Update its data as adding all the header and data of its child node.\r | |
326 | for item in ParTree.Child:\r | |
327 | if item.type == SECTION_TREE and item.Data.ExtHeader and item.Data.Type != 0x02:\r | |
328 | ParTree.Data.Data += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.Data + item.Data.PadData\r | |
329 | elif item.type == SECTION_TREE and item.Data.ExtHeader and item.Data.Type == 0x02:\r | |
330 | ParTree.Data.Data += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.OriData + item.Data.PadData\r | |
331 | else:\r | |
332 | ParTree.Data.Data += struct2stream(item.Data.Header) + item.Data.Data + item.Data.PadData\r | |
333 | # If the current section is guided section\r | |
334 | if ParTree.Data.Type == 0x02:\r | |
335 | guidtool = GUIDTools().__getitem__(struct2stream(ParTree.Data.ExtHeader.SectionDefinitionGuid))\r | |
336 | if not guidtool.ifexist:\r | |
337 | logger.error("GuidTool {} is not found when decompressing {} file.\n".format(guidtool.command, ParTree.Parent.Data.Name))\r | |
338 | raise Exception("Process Failed: GuidTool not found!")\r | |
339 | # Recompress current data, and recalculate the needed space\r | |
340 | CompressedData = guidtool.pack(ParTree.Data.Data)\r | |
341 | Needed_Space = len(CompressedData) - len(ParTree.Data.OriData)\r | |
342 | ParTree.Data.OriData = CompressedData\r | |
343 | New_Size = ParTree.Data.HeaderLength + len(CompressedData)\r | |
344 | ParTree.Data.Header.Size[0] = New_Size % (16**2)\r | |
345 | ParTree.Data.Header.Size[1] = New_Size % (16**4) //(16**2)\r | |
346 | ParTree.Data.Header.Size[2] = New_Size // (16**4)\r | |
347 | ParTree.Data.Size = ParTree.Data.Header.SECTION_SIZE\r | |
348 | ModifySectionType(ParTree)\r | |
349 | Needed_Space += ParTree.Data.HeaderLength - OriHeaderLen\r | |
350 | # Update needed space with Delta_Pad_Size\r | |
351 | if ParTree.NextRel:\r | |
352 | New_Pad_Size = GetPadSize(ParTree.Data.Size, SECTION_COMMON_ALIGNMENT)\r | |
353 | Delta_Pad_Size = New_Pad_Size - len(ParTree.Data.PadData)\r | |
354 | ParTree.Data.PadData = b'\x00' * New_Pad_Size\r | |
355 | Needed_Space += Delta_Pad_Size\r | |
356 | else:\r | |
357 | ParTree.Data.PadData = b''\r | |
358 | if Needed_Space < 0:\r | |
359 | self.Remain_New_Free_Space = len(ParTree.Data.OriData) - len(CompressedData)\r | |
360 | # If current section is not guided section\r | |
361 | elif Needed_Space:\r | |
362 | ChangeSize(ParTree, -Needed_Space)\r | |
363 | ModifySectionType(ParTree)\r | |
364 | # Update needed space with Delta_Pad_Size\r | |
365 | Needed_Space += ParTree.Data.HeaderLength - OriHeaderLen\r | |
366 | New_Pad_Size = GetPadSize(ParTree.Data.Size, SECTION_COMMON_ALIGNMENT)\r | |
367 | Delta_Pad_Size = New_Pad_Size - len(ParTree.Data.PadData)\r | |
368 | Needed_Space += Delta_Pad_Size\r | |
369 | ParTree.Data.PadData = b'\x00' * New_Pad_Size\r | |
370 | NewParTree = ParTree.Parent\r | |
371 | ROOT_TYPE = [ROOT_FV_TREE, ROOT_FFS_TREE, ROOT_SECTION_TREE, ROOT_TREE]\r | |
372 | if NewParTree and NewParTree.type not in ROOT_TYPE:\r | |
373 | self.ModifyTest(NewParTree, Needed_Space)\r | |
374 | # If current node have enough space, will recompress all the related node data, return true.\r | |
375 | else:\r | |
376 | self.CompressData(ParTree)\r | |
377 | self.Status = True\r | |
378 | \r | |
379 | def ReplaceFfs(self) -> bool:\r | |
380 | logger.debug('Start Replacing Process......')\r | |
381 | TargetFv = self.TargetFfs.Parent\r | |
382 | # If the Fv Header Attributes is EFI_FVB2_ERASE_POLARITY, Child Ffs Header State need be reversed.\r | |
383 | if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY:\r | |
384 | self.NewFfs.Data.Header.State = c_uint8(\r | |
385 | ~self.NewFfs.Data.Header.State)\r | |
386 | # NewFfs parsing will not calculate the PadSize, thus recalculate.\r | |
387 | self.NewFfs.Data.PadData = b'\xff' * GetPadSize(self.NewFfs.Data.Size, FFS_COMMON_ALIGNMENT)\r | |
388 | if self.NewFfs.Data.Size >= self.TargetFfs.Data.Size:\r | |
389 | Needed_Space = self.NewFfs.Data.Size + len(self.NewFfs.Data.PadData) - self.TargetFfs.Data.Size - len(self.TargetFfs.Data.PadData)\r | |
390 | # If TargetFv have enough free space, just move part of the free space to NewFfs.\r | |
391 | if TargetFv.Data.Free_Space >= Needed_Space:\r | |
392 | # Modify TargetFv Child info and BiosTree.\r | |
393 | TargetFv.Child[-1].Data.Data = b'\xff' * (TargetFv.Data.Free_Space - Needed_Space)\r | |
394 | TargetFv.Data.Free_Space -= Needed_Space\r | |
395 | Target_index = TargetFv.Child.index(self.TargetFfs)\r | |
396 | TargetFv.Child.remove(self.TargetFfs)\r | |
397 | TargetFv.insertChild(self.NewFfs, Target_index)\r | |
398 | # Modify TargetFv Header and ExtHeader info.\r | |
399 | TargetFv.Data.ModFvExt()\r | |
400 | TargetFv.Data.ModFvSize()\r | |
401 | TargetFv.Data.ModExtHeaderData()\r | |
402 | ModifyFvExtData(TargetFv)\r | |
403 | TargetFv.Data.ModCheckSum()\r | |
404 | # Recompress from the Fv node to update all the related node data.\r | |
405 | self.CompressData(TargetFv)\r | |
406 | # return the Status\r | |
407 | self.Status = True\r | |
408 | # If TargetFv do not have enough free space, need move part of the free space of TargetFv's parent Fv to TargetFv/NewFfs.\r | |
409 | else:\r | |
410 | if TargetFv.type == FV_TREE:\r | |
411 | self.Status = False\r | |
412 | else:\r | |
413 | # Recalculate TargetFv needed space to keep it match the BlockSize setting.\r | |
414 | Needed_Space -= TargetFv.Data.Free_Space\r | |
415 | BlockSize = TargetFv.Data.Header.BlockMap[0].Length\r | |
416 | New_Add_Len = BlockSize - Needed_Space%BlockSize\r | |
417 | Target_index = TargetFv.Child.index(self.TargetFfs)\r | |
418 | if New_Add_Len % BlockSize:\r | |
419 | TargetFv.Child[-1].Data.Data = b'\xff' * New_Add_Len\r | |
420 | TargetFv.Data.Free_Space = New_Add_Len\r | |
421 | Needed_Space += New_Add_Len\r | |
422 | TargetFv.insertChild(self.NewFfs, Target_index)\r | |
423 | TargetFv.Child.remove(self.TargetFfs)\r | |
424 | else:\r | |
425 | TargetFv.Child.remove(self.TargetFfs)\r | |
426 | TargetFv.Data.Free_Space = 0\r | |
427 | TargetFv.insertChild(self.NewFfs)\r | |
428 | # Encapsulate the Fv Data for update.\r | |
429 | TargetFv.Data.Data = b''\r | |
430 | for item in TargetFv.Child:\r | |
431 | if item.type == FFS_FREE_SPACE:\r | |
432 | TargetFv.Data.Data += item.Data.Data + item.Data.PadData\r | |
433 | else:\r | |
434 | TargetFv.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData\r | |
435 | TargetFv.Data.Size += Needed_Space\r | |
436 | # Modify TargetFv Data Header and ExtHeader info.\r | |
437 | TargetFv.Data.Header.FvLength = TargetFv.Data.Size\r | |
438 | TargetFv.Data.ModFvExt()\r | |
439 | TargetFv.Data.ModFvSize()\r | |
440 | TargetFv.Data.ModExtHeaderData()\r | |
441 | ModifyFvExtData(TargetFv)\r | |
442 | TargetFv.Data.ModCheckSum()\r | |
443 | # Start free space calculating and moving process.\r | |
444 | self.ModifyTest(TargetFv.Parent, Needed_Space)\r | |
445 | else:\r | |
446 | New_Free_Space = self.TargetFfs.Data.Size - self.NewFfs.Data.Size\r | |
447 | # If TargetFv already have free space, move the new free space into it.\r | |
448 | if TargetFv.Data.Free_Space:\r | |
449 | TargetFv.Child[-1].Data.Data += b'\xff' * New_Free_Space\r | |
450 | TargetFv.Data.Free_Space += New_Free_Space\r | |
451 | Target_index = TargetFv.Child.index(self.TargetFfs)\r | |
452 | TargetFv.Child.remove(self.TargetFfs)\r | |
453 | TargetFv.insertChild(self.NewFfs, Target_index)\r | |
454 | self.Status = True\r | |
455 | # If TargetFv do not have free space, create free space for Fv.\r | |
456 | else:\r | |
457 | New_Free_Space_Tree = BIOSTREE('FREE_SPACE')\r | |
458 | New_Free_Space_Tree.type = FFS_FREE_SPACE\r | |
459 | New_Free_Space_Tree.Data = FfsNode(b'\xff' * New_Free_Space)\r | |
460 | TargetFv.Data.Free_Space = New_Free_Space\r | |
461 | TargetFv.insertChild(New_Free_Space)\r | |
462 | Target_index = TargetFv.Child.index(self.TargetFfs)\r | |
463 | TargetFv.Child.remove(self.TargetFfs)\r | |
464 | TargetFv.insertChild(self.NewFfs, Target_index)\r | |
465 | self.Status = True\r | |
466 | # Modify TargetFv Header and ExtHeader info.\r | |
467 | TargetFv.Data.ModFvExt()\r | |
468 | TargetFv.Data.ModFvSize()\r | |
469 | TargetFv.Data.ModExtHeaderData()\r | |
470 | ModifyFvExtData(TargetFv)\r | |
471 | TargetFv.Data.ModCheckSum()\r | |
472 | # Recompress from the Fv node to update all the related node data.\r | |
473 | self.CompressData(TargetFv)\r | |
474 | logger.debug('Done!')\r | |
475 | return self.Status\r | |
476 | \r | |
477 | def AddFfs(self) -> bool:\r | |
478 | logger.debug('Start Adding Process......')\r | |
479 | # NewFfs parsing will not calculate the PadSize, thus recalculate.\r | |
480 | self.NewFfs.Data.PadData = b'\xff' * GetPadSize(self.NewFfs.Data.Size, FFS_COMMON_ALIGNMENT)\r | |
481 | if self.TargetFfs.type == FFS_FREE_SPACE:\r | |
482 | TargetLen = self.NewFfs.Data.Size + len(self.NewFfs.Data.PadData) - self.TargetFfs.Data.Size - len(self.TargetFfs.Data.PadData)\r | |
483 | TargetFv = self.TargetFfs.Parent\r | |
484 | # If the Fv Header Attributes is EFI_FVB2_ERASE_POLARITY, Child Ffs Header State need be reversed.\r | |
485 | if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY:\r | |
486 | self.NewFfs.Data.Header.State = c_uint8(\r | |
487 | ~self.NewFfs.Data.Header.State)\r | |
488 | # If TargetFv have enough free space, just move part of the free space to NewFfs, split free space to NewFfs and new free space.\r | |
489 | if TargetLen < 0:\r | |
490 | self.Status = True\r | |
491 | self.TargetFfs.Data.Data = b'\xff' * (-TargetLen)\r | |
492 | TargetFv.Data.Free_Space = (-TargetLen)\r | |
493 | TargetFv.Data.ModFvExt()\r | |
494 | TargetFv.Data.ModExtHeaderData()\r | |
495 | ModifyFvExtData(TargetFv)\r | |
496 | TargetFv.Data.ModCheckSum()\r | |
497 | TargetFv.insertChild(self.NewFfs, -1)\r | |
498 | ModifyFfsType(self.NewFfs)\r | |
499 | # Recompress from the Fv node to update all the related node data.\r | |
500 | self.CompressData(TargetFv)\r | |
501 | elif TargetLen == 0:\r | |
502 | self.Status = True\r | |
503 | TargetFv.Child.remove(self.TargetFfs)\r | |
504 | TargetFv.insertChild(self.NewFfs)\r | |
505 | ModifyFfsType(self.NewFfs)\r | |
506 | # Recompress from the Fv node to update all the related node data.\r | |
507 | self.CompressData(TargetFv)\r | |
508 | # If TargetFv do not have enough free space, need move part of the free space of TargetFv's parent Fv to TargetFv/NewFfs.\r | |
509 | else:\r | |
510 | if TargetFv.type == FV_TREE:\r | |
511 | self.Status = False\r | |
512 | elif TargetFv.type == SEC_FV_TREE:\r | |
513 | # Recalculate TargetFv needed space to keep it match the BlockSize setting.\r | |
514 | BlockSize = TargetFv.Data.Header.BlockMap[0].Length\r | |
515 | New_Add_Len = BlockSize - TargetLen%BlockSize\r | |
516 | if New_Add_Len % BlockSize:\r | |
517 | self.TargetFfs.Data.Data = b'\xff' * New_Add_Len\r | |
518 | self.TargetFfs.Data.Size = New_Add_Len\r | |
519 | TargetLen += New_Add_Len\r | |
520 | TargetFv.insertChild(self.NewFfs, -1)\r | |
521 | TargetFv.Data.Free_Space = New_Add_Len\r | |
522 | else:\r | |
523 | TargetFv.Child.remove(self.TargetFfs)\r | |
524 | TargetFv.insertChild(self.NewFfs)\r | |
525 | TargetFv.Data.Free_Space = 0\r | |
526 | ModifyFfsType(self.NewFfs)\r | |
527 | ModifyFvSystemGuid(TargetFv)\r | |
528 | TargetFv.Data.Data = b''\r | |
529 | for item in TargetFv.Child:\r | |
530 | if item.type == FFS_FREE_SPACE:\r | |
531 | TargetFv.Data.Data += item.Data.Data + item.Data.PadData\r | |
532 | else:\r | |
533 | TargetFv.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData\r | |
534 | # Encapsulate the Fv Data for update.\r | |
535 | TargetFv.Data.Size += TargetLen\r | |
536 | TargetFv.Data.Header.FvLength = TargetFv.Data.Size\r | |
537 | TargetFv.Data.ModFvExt()\r | |
538 | TargetFv.Data.ModFvSize()\r | |
539 | TargetFv.Data.ModExtHeaderData()\r | |
540 | ModifyFvExtData(TargetFv)\r | |
541 | TargetFv.Data.ModCheckSum()\r | |
542 | # Start free space calculating and moving process.\r | |
543 | self.ModifyTest(TargetFv.Parent, TargetLen)\r | |
544 | else:\r | |
545 | # If TargetFv do not have free space, need directly move part of the free space of TargetFv's parent Fv to TargetFv/NewFfs.\r | |
546 | TargetLen = self.NewFfs.Data.Size + len(self.NewFfs.Data.PadData)\r | |
547 | TargetFv = self.TargetFfs.Parent\r | |
548 | if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY:\r | |
549 | self.NewFfs.Data.Header.State = c_uint8(\r | |
550 | ~self.NewFfs.Data.Header.State)\r | |
551 | if TargetFv.type == FV_TREE:\r | |
552 | self.Status = False\r | |
553 | elif TargetFv.type == SEC_FV_TREE:\r | |
554 | BlockSize = TargetFv.Data.Header.BlockMap[0].Length\r | |
555 | New_Add_Len = BlockSize - TargetLen%BlockSize\r | |
556 | if New_Add_Len % BlockSize:\r | |
557 | New_Free_Space = BIOSTREE('FREE_SPACE')\r | |
558 | New_Free_Space.type = FFS_FREE_SPACE\r | |
559 | New_Free_Space.Data = FreeSpaceNode(b'\xff' * New_Add_Len)\r | |
560 | TargetLen += New_Add_Len\r | |
561 | TargetFv.Data.Free_Space = New_Add_Len\r | |
562 | TargetFv.insertChild(self.NewFfs)\r | |
563 | TargetFv.insertChild(New_Free_Space)\r | |
564 | else:\r | |
565 | TargetFv.insertChild(self.NewFfs)\r | |
566 | ModifyFfsType(self.NewFfs)\r | |
567 | ModifyFvSystemGuid(TargetFv)\r | |
568 | TargetFv.Data.Data = b''\r | |
569 | for item in TargetFv.Child:\r | |
570 | if item.type == FFS_FREE_SPACE:\r | |
571 | TargetFv.Data.Data += item.Data.Data + item.Data.PadData\r | |
572 | else:\r | |
573 | TargetFv.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData\r | |
574 | TargetFv.Data.Size += TargetLen\r | |
575 | TargetFv.Data.Header.FvLength = TargetFv.Data.Size\r | |
576 | TargetFv.Data.ModFvExt()\r | |
577 | TargetFv.Data.ModFvSize()\r | |
578 | TargetFv.Data.ModExtHeaderData()\r | |
579 | ModifyFvExtData(TargetFv)\r | |
580 | TargetFv.Data.ModCheckSum()\r | |
581 | self.ModifyTest(TargetFv.Parent, TargetLen)\r | |
582 | logger.debug('Done!')\r | |
583 | return self.Status\r | |
584 | \r | |
585 | def DeleteFfs(self) -> bool:\r | |
586 | logger.debug('Start Deleting Process......')\r | |
587 | Delete_Ffs = self.TargetFfs\r | |
588 | Delete_Fv = Delete_Ffs.Parent\r | |
589 | # Calculate free space\r | |
590 | Add_Free_Space = Delete_Ffs.Data.Size + len(Delete_Ffs.Data.PadData)\r | |
591 | # If Ffs parent Fv have free space, follow the rules to merge the new free space.\r | |
592 | if Delete_Fv.Data.Free_Space:\r | |
593 | # If Fv is a Section fv, free space need to be recalculated to keep align with BlockSize.\r | |
594 | # Other free space saved in self.Remain_New_Free_Space, will be moved to the 1st level Fv.\r | |
595 | if Delete_Fv.type == SEC_FV_TREE:\r | |
596 | Used_Size = Delete_Fv.Data.Size - Delete_Fv.Data.Free_Space - Add_Free_Space\r | |
597 | BlockSize = Delete_Fv.Data.Header.BlockMap[0].Length\r | |
598 | New_Free_Space = BlockSize - Used_Size % BlockSize\r | |
599 | self.Remain_New_Free_Space += Delete_Fv.Data.Free_Space + Add_Free_Space - New_Free_Space\r | |
600 | Delete_Fv.Child[-1].Data.Data = New_Free_Space * b'\xff'\r | |
601 | Delete_Fv.Data.Free_Space = New_Free_Space\r | |
602 | # If Fv is lst level Fv, new free space will be merged with origin free space.\r | |
603 | else:\r | |
604 | Used_Size = Delete_Fv.Data.Size - Delete_Fv.Data.Free_Space - Add_Free_Space\r | |
605 | Delete_Fv.Child[-1].Data.Data += Add_Free_Space * b'\xff'\r | |
606 | Delete_Fv.Data.Free_Space += Add_Free_Space\r | |
607 | New_Free_Space = Delete_Fv.Data.Free_Space\r | |
608 | # If Ffs parent Fv not have free space, will create new free space node to save the free space.\r | |
609 | else:\r | |
610 | # If Fv is a Section fv, new free space need to be recalculated to keep align with BlockSize.\r | |
611 | # Then create a Free spcae node to save the 0xff data, and insert into the Fv.\r | |
612 | # If have more space left, move to 1st level fv.\r | |
613 | if Delete_Fv.type == SEC_FV_TREE:\r | |
614 | Used_Size = Delete_Fv.Data.Size - Add_Free_Space\r | |
615 | BlockSize = Delete_Fv.Data.Header.BlockMap[0].Length\r | |
616 | New_Free_Space = BlockSize - Used_Size % BlockSize\r | |
617 | self.Remain_New_Free_Space += Add_Free_Space - New_Free_Space\r | |
618 | Add_Free_Space = New_Free_Space\r | |
619 | # If Fv is lst level Fv, new free space node will be created to save the free space.\r | |
620 | else:\r | |
621 | Used_Size = Delete_Fv.Data.Size - Add_Free_Space\r | |
622 | New_Free_Space = Add_Free_Space\r | |
623 | New_Free_Space_Info = FfsNode(Add_Free_Space * b'\xff')\r | |
624 | New_Free_Space_Info.Data = Add_Free_Space * b'\xff'\r | |
625 | New_Ffs_Tree = BIOSTREE(New_Free_Space_Info.Name)\r | |
626 | New_Ffs_Tree.type = FFS_FREE_SPACE\r | |
627 | New_Ffs_Tree.Data = New_Free_Space_Info\r | |
628 | Delete_Fv.insertChild(New_Ffs_Tree)\r | |
629 | Delete_Fv.Data.Free_Space = Add_Free_Space\r | |
630 | Delete_Fv.Child.remove(Delete_Ffs)\r | |
631 | Delete_Fv.Data.Header.FvLength = Used_Size + New_Free_Space\r | |
632 | Delete_Fv.Data.ModFvExt()\r | |
633 | Delete_Fv.Data.ModFvSize()\r | |
634 | Delete_Fv.Data.ModExtHeaderData()\r | |
635 | ModifyFvExtData(Delete_Fv)\r | |
636 | Delete_Fv.Data.ModCheckSum()\r | |
637 | # Recompress from the Fv node to update all the related node data.\r | |
638 | self.CompressData(Delete_Fv)\r | |
639 | self.Status = True\r | |
640 | logger.debug('Done!')\r | |
641 | return self.Status\r |