VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/UefiPayloadPkg/Tools/MkFitImage.py@ 107365

Last change on this file since 107365 was 105670, checked in by vboxsync, 9 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 12.3 KB
Line 
1## @file
2# This file is a script to build fit image.
3# It generate a dtb header and combine a binary file after this header.
4#
5# Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
6# SPDX-License-Identifier: BSD-2-Clause-Patent
7##
8
9from os.path import exists
10import libfdt
11from ctypes import *
12import time
13import os
14
15class FIT_IMAGE_INFO_HEADER:
16 """Class for user setting data to use MakeFitImage()
17 """
18 _pack_ = 1
19 _fields_ = [
20 ('Compatible', str),
21 ('UplVersion', int),
22 ('Description', str),
23 ('Type', str),
24 ('Arch', str),
25 ('Compression', str),
26 ('Revision', int),
27 ('BuildType', str),
28 ('Capabilities', str),
29 ('Producer', str),
30 ('ImageId', str),
31 ('DataOffset', int),
32 ('DataSize', int),
33 ('RelocStart', int),
34 ('LoadAddr', int),
35 ('Entry', int),
36 ('Binary', str),
37 ('TargetPath', str),
38 ('UefifvPath', str),
39 ('BdsfvPath', str),
40 ('NetworkfvPath', str),
41 ('Project', str),
42 ]
43
44 def __init__(self):
45 self.Compatible = 'universal-payload'
46 self.UplVersion = 0x0100
47 self.TargetPath = 'mkimage.fit'
48
49def CreatFdt(Fdt):
50 FdtEmptyTree = libfdt.fdt_create_empty_tree(Fdt, len(Fdt))
51 if FdtEmptyTree != 0:
52 print('\n- Failed - Create Fdt failed!')
53 return False
54 return True
55
56def BuildConfNode(Fdt, ParentNode, MultiImage):
57 ConfNode1 = libfdt.fdt_add_subnode(Fdt, ParentNode, 'conf-1')
58
59 libfdt.fdt_setprop(Fdt, ConfNode1, 'require-fit', b'', 0)
60 libfdt.fdt_setprop(Fdt, ConfNode1, 'firmware', bytes('tianocore', 'utf-8'), len('tianocore') + 1)
61
62def BuildFvImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description, Arch):
63 libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize)
64 libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset)
65 libfdt.fdt_setprop(Fdt, ParentNode, 'compression', bytes('none', 'utf-8'), len('none') + 1)
66 libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes('tianocore', 'utf-8'), len('tianocore') + 1)
67 libfdt.fdt_setprop(Fdt, ParentNode, 'arch', bytes(Arch, 'utf-8'), len(Arch) + 1)
68 libfdt.fdt_setprop(Fdt, ParentNode, 'type', bytes('flat-binary', 'utf-8'), len('flat-binary') + 1)
69 libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, 'utf-8'), len(Description) + 1)
70
71def BuildTianoImageNode(Fdt, InfoHeader, ParentNode, DataOffset, DataSize, Description, Arch):
72 #
73 # Set 'load' and 'data-offset' to reserve the memory first.
74 # They would be set again when Fdt completes or this function parses target binary file.
75 #
76 if InfoHeader.LoadAddr is not None:
77 libfdt.fdt_setprop_u64(Fdt, ParentNode, 'load', InfoHeader.LoadAddr)
78 if InfoHeader.Entry is not None:
79 libfdt.fdt_setprop_u64(Fdt, ParentNode, 'entry-start', InfoHeader.Entry)
80 if InfoHeader.RelocStart is not None:
81 libfdt.fdt_setprop_u32(Fdt, ParentNode, 'reloc-start', InfoHeader.RelocStart)
82 if InfoHeader.DataSize is not None:
83 libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-size', DataSize)
84 if InfoHeader.DataOffset is not None:
85 libfdt.fdt_setprop_u32(Fdt, ParentNode, 'data-offset', DataOffset)
86 if InfoHeader.Producer is not None:
87 libfdt.fdt_setprop(Fdt, ParentNode, 'producer ', bytes(InfoHeader.Producer, 'utf-8'), len(InfoHeader.Producer) + 1)
88 if InfoHeader.Capabilities is not None:
89 CapStrs = ','.join(InfoHeader.Capabilities)
90 libfdt.fdt_setprop(Fdt, ParentNode, 'capabilities ', bytes(CapStrs, 'utf-8'), len(CapStrs) + 1)
91 if InfoHeader.Type is not None:
92 libfdt.fdt_setprop(Fdt, ParentNode, 'type ', bytes(InfoHeader.Type, 'utf-8'), len(InfoHeader.Type) + 1)
93 if InfoHeader.Arch is not None:
94 libfdt.fdt_setprop(Fdt, ParentNode, 'arch ', bytes(InfoHeader.Arch, 'utf-8'), len(InfoHeader.Arch) + 1)
95 if InfoHeader.Project is not None:
96 libfdt.fdt_setprop(Fdt, ParentNode, 'project ', bytes(InfoHeader.Project, 'utf-8'), len(InfoHeader.Project) + 1)
97 if InfoHeader.Description is not None:
98 libfdt.fdt_setprop(Fdt, ParentNode, 'description', bytes(Description, 'utf-8'), len(Description) + 1)
99
100#
101# The subnode would be inserted from bottom to top of structure block.
102#
103def BuildFitImage(Fdt, InfoHeader, Arch):
104 MultiImage = [
105 ["tianocore", InfoHeader.Binary, BuildTianoImageNode , InfoHeader.Description, None, 0 ],
106 ["uefi-fv", InfoHeader.UefifvPath, BuildFvImageNode, "UEFI Firmware Volume", None, 0 ],
107 ["bds-fv", InfoHeader.BdsfvPath, BuildFvImageNode , "BDS Firmware Volume", None, 0 ],
108 ["network-fv", InfoHeader.NetworkfvPath, BuildFvImageNode , "Network Firmware Volume", None, 0 ],
109 ]
110
111 #
112 # Set basic information
113 #
114 libfdt.fdt_setprop_u32(Fdt, 0, 'build-revision ', InfoHeader.Revision)
115 libfdt.fdt_setprop_u32(Fdt, 0, 'spec-version', InfoHeader.UplVersion)
116
117 #
118 # Build configurations node
119 #
120 ConfNode = libfdt.fdt_add_subnode(Fdt, 0, 'configurations')
121 BuildConfNode(Fdt, ConfNode, MultiImage)
122
123 # Build image
124 DataOffset = InfoHeader.DataOffset
125 for Index in range (0, len (MultiImage)):
126 _, Path, _, _, _, _ = MultiImage[Index]
127 if exists(Path) == 1:
128 TempBinary = open(Path, 'rb')
129 BinaryData = TempBinary.read()
130 TempBinary.close()
131 MultiImage[Index][-2] = BinaryData
132 MultiImage[Index][-1] = DataOffset
133 DataOffset += len (BinaryData)
134 libfdt.fdt_setprop_u32(Fdt, 0, 'size', DataOffset)
135 posix_time = int(time.time())
136 libfdt.fdt_setprop_u32(Fdt, 0, 'timestamp', posix_time)
137 DescriptionFit = 'Uefi OS Loader'
138 libfdt.fdt_setprop(Fdt, 0, 'description', bytes(DescriptionFit, 'utf-8'), len(DescriptionFit) + 1)
139
140 ImageNode = libfdt.fdt_add_subnode(Fdt, 0, 'images')
141 for Item in reversed (MultiImage):
142 Name, Path, BuildFvNode, Description, BinaryData, DataOffset = Item
143 if os.path.exists (Item[1]) == False:
144 continue
145 FvNode = libfdt.fdt_add_subnode(Fdt, ImageNode, Name)
146 BuildFvNode (Fdt, InfoHeader, FvNode, DataOffset, len(BinaryData), Description, Arch)
147
148 #
149 # Create new image file and combine all binary.
150 #
151 DtbFile = open(InfoHeader.TargetPath, "wb")
152 DtbFile.truncate()
153 DtbFile.write(Fdt)
154 for Item in MultiImage:
155 _, FilePath, _, _, BinaryData, _ = Item
156 if os.path.exists (Item[1]) == False:
157 continue
158 DtbFile.write(BinaryData)
159 DtbFile.close()
160
161 return True
162
163def MakeFitImage(InfoHeader, Arch):
164 #
165 # Allocate fdt byte array.
166 #
167 Fdt = bytearray(InfoHeader.DataOffset)
168
169 #
170 # Create fdt empty tree.
171 #
172 if CreatFdt(Fdt) is False:
173 return False
174
175 #
176 # Parse args to build fit image.
177 #
178 return BuildFitImage(Fdt, InfoHeader, Arch)
179
180def ReplaceFv (UplBinary, SectionFvFile, SectionName, Arch):
181 try:
182 #
183 # Get Original Multi Fv
184 #
185 with open (UplBinary, "rb") as File:
186 Dtb = File.read ()
187 Fit = libfdt.Fdt (Dtb)
188 NewFitHeader = bytearray(Dtb[0:Fit.totalsize()])
189 FitSize = len(Dtb)
190
191 LoadablesList = []
192 ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images')
193 FvNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'uefi-fv')
194 NodeDepth = libfdt.fdt_node_depth (NewFitHeader, ImagesNode)
195 node_name = libfdt.fdt_get_name(NewFitHeader, FvNode)
196 FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode, NodeDepth)
197
198 while node_name[0][-2:] == 'fv':
199 LoadablesList.append (node_name[0])
200 node_name = libfdt.fdt_get_name(NewFitHeader, FvNode[0])
201 FvNode = libfdt.fdt_next_node(NewFitHeader, FvNode[0], NodeDepth)
202 #
203 # Get current Fit Binary FV data
204 #
205 MultiFvList = []
206 for Item in LoadablesList:
207 ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, Item)
208 ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
209 ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big')
210 MultiFvList.append ([Item, Dtb[ImageOffset:ImageOffset + ImageSize]])
211
212 IsFvExist = False
213 for Index in range (0, len (MultiFvList)):
214 if MultiFvList[Index][0] == SectionName:
215 with open (SectionFvFile, 'rb') as File:
216 MultiFvList[Index][1] = File.read ()
217 ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, SectionName)
218 ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big')
219 ReplaceOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
220 OffsetDelta = len(MultiFvList[Index][1]) - ImageSize
221 FitSize += OffsetDelta
222 IsFvExist = True
223 libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-size', len(MultiFvList[Index][1]))
224
225 #
226 # Update new fit header
227 #
228 ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images')
229 if (IsFvExist == False):
230 with open (SectionFvFile, 'rb') as File:
231 SectionFvFileBinary = File.read ()
232 MultiFvList.append ([SectionName, SectionFvFileBinary])
233 FvNode = libfdt.fdt_add_subnode(NewFitHeader, ImagesNode, SectionName)
234 BuildFvImageNode (NewFitHeader, None, FvNode, FitSize, len(SectionFvFileBinary), SectionName + " Firmware Volume", Arch)
235 FitSize += len(SectionFvFileBinary)
236 else:
237 for Index in range (0, len (MultiFvList)):
238 ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0])
239 ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
240 if ImageOffset > ReplaceOffset:
241 libfdt.fdt_setprop_u32(NewFitHeader, ImageNode, 'data-offset', ImageOffset + OffsetDelta)
242
243 ConfNodes = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'configurations')
244 libfdt.fdt_setprop(NewFitHeader, ConfNodes, 'default ', bytes('conf-1', 'utf-8'), len('conf-1') + 1)
245 ConfNode = libfdt.fdt_subnode_offset(NewFitHeader, ConfNodes, 'conf-1')
246
247 libfdt.fdt_setprop_u32(NewFitHeader, 0, 'size', FitSize)
248
249 #
250 # Generate new fit image
251 #
252 ImagesNode = libfdt.fdt_subnode_offset(NewFitHeader, 0, 'images')
253 TianoNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, 'tianocore')
254 TianoOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-offset')[0], 'big')
255 TianoSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, TianoNode, 'data-size')[0], 'big')
256 TianoBinary = Dtb[TianoOffset:TianoOffset + TianoSize]
257
258 print("\nGenerate new fit image:")
259 NewUplBinary = bytearray(FitSize)
260 print("Update fit header\t to 0x0\t\t ~ " + str(hex(len(NewFitHeader))))
261 NewUplBinary[:len(NewFitHeader)] = NewFitHeader
262 print("Update tiano image\t to " + str(hex(len(NewFitHeader))) + "\t ~ " + str(hex(len(NewFitHeader) + len(TianoBinary))))
263 NewUplBinary[len(NewFitHeader):len(NewFitHeader) + len(TianoBinary)] = TianoBinary
264 for Index in range (0, len (MultiFvList)):
265 ImageNode = libfdt.fdt_subnode_offset(NewFitHeader, ImagesNode, MultiFvList[Index][0])
266 ImageOffset = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-offset')[0], 'big')
267 ImageSize = int.from_bytes (libfdt.fdt_getprop (NewFitHeader, ImageNode, 'data-size')[0], 'big')
268 NewUplBinary[ImageOffset:ImageOffset + ImageSize] = MultiFvList[Index][1]
269 print("Update " + MultiFvList[Index][0] + "\t\t to " + str(hex(ImageOffset)) + "\t ~ " + str(hex(ImageOffset + ImageSize)))
270
271 with open (UplBinary, "wb") as File:
272 File.write (NewUplBinary)
273
274 return 0
275 except Exception as Ex:
276 print(Ex)
277 return 1
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette