]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/FMMT/core/FvHandler.py
BaseTools: Add FMMT Python Tool
[mirror_edk2.git] / BaseTools / Source / Python / FMMT / core / FvHandler.py
CommitLineData
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
7import os\r
8from core.BiosTree import *\r
9from core.GuidTools import GUIDTools\r
10from core.BiosTreeNode import *\r
11from FirmwareStorageFormat.Common import *\r
12from utils.FmmtLogger import FmmtLogger as logger\r
13\r
14EFI_FVB2_ERASE_POLARITY = 0x00000800\r
15\r
16def 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
33def 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
80def 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
85def 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
123def 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
136def 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
147class 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