]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/PlatformCI/PlatformBuild.py
PcAtChipsetPkg: Move RTC PCD to dynamic PCD
[mirror_edk2.git] / ArmVirtPkg / PlatformCI / PlatformBuild.py
1 # @file
2 # Script to Build ArmVirtPkg UEFI firmware
3 #
4 # Copyright (c) Microsoft Corporation.
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
6 ##
7 import os
8 import logging
9 import io
10
11 from edk2toolext.environment import shell_environment
12 from edk2toolext.environment.uefi_build import UefiBuilder
13 from edk2toolext.invocables.edk2_platform_build import BuildSettingsManager
14 from edk2toolext.invocables.edk2_setup import SetupSettingsManager, RequiredSubmodule
15 from edk2toolext.invocables.edk2_update import UpdateSettingsManager
16 from edk2toolext.invocables.edk2_pr_eval import PrEvalSettingsManager
17 from edk2toollib.utility_functions import RunCmd
18 from edk2toollib.utility_functions import GetHostInfo
19
20 # ####################################################################################### #
21 # Common Configuration #
22 # ####################################################################################### #
23
24
25 class CommonPlatform():
26 ''' Common settings for this platform. Define static data here and use
27 for the different parts of stuart
28 '''
29 PackagesSupported = ("ArmVirtPkg",)
30 ArchSupported = ("AARCH64", "ARM")
31 TargetsSupported = ("DEBUG", "RELEASE", "NOOPT")
32 Scopes = ('armvirt', 'edk2-build')
33 WorkspaceRoot = os.path.realpath(os.path.join(
34 os.path.dirname(os.path.abspath(__file__)), "..", ".."))
35
36 # ####################################################################################### #
37 # Configuration for Update & Setup #
38 # ####################################################################################### #
39
40
41 class SettingsManager(UpdateSettingsManager, SetupSettingsManager, PrEvalSettingsManager):
42
43 def GetPackagesSupported(self):
44 ''' return iterable of edk2 packages supported by this build.
45 These should be edk2 workspace relative paths '''
46 return CommonPlatform.PackagesSupported
47
48 def GetArchitecturesSupported(self):
49 ''' return iterable of edk2 architectures supported by this build '''
50 return CommonPlatform.ArchSupported
51
52 def GetTargetsSupported(self):
53 ''' return iterable of edk2 target tags supported by this build '''
54 return CommonPlatform.TargetsSupported
55
56 def GetRequiredSubmodules(self):
57 ''' return iterable containing RequiredSubmodule objects.
58 If no RequiredSubmodules return an empty iterable
59 '''
60 rs = []
61
62 # intentionally declare this one with recursive false to avoid overhead
63 rs.append(RequiredSubmodule(
64 "CryptoPkg/Library/OpensslLib/openssl", False))
65
66 # To avoid maintenance of this file for every new submodule
67 # lets just parse the .gitmodules and add each if not already in list.
68 # The GetRequiredSubmodules is designed to allow a build to optimize
69 # the desired submodules but it isn't necessary for this repository.
70 result = io.StringIO()
71 ret = RunCmd("git", "config --file .gitmodules --get-regexp path", workingdir=self.GetWorkspaceRoot(), outstream=result)
72 # Cmd output is expected to look like:
73 # submodule.CryptoPkg/Library/OpensslLib/openssl.path CryptoPkg/Library/OpensslLib/openssl
74 # submodule.SoftFloat.path ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3
75 if ret == 0:
76 for line in result.getvalue().splitlines():
77 _, _, path = line.partition(" ")
78 if path is not None:
79 if path not in [x.path for x in rs]:
80 rs.append(RequiredSubmodule(path, True)) # add it with recursive since we don't know
81 return rs
82
83 def SetArchitectures(self, list_of_requested_architectures):
84 ''' Confirm the requests architecture list is valid and configure SettingsManager
85 to run only the requested architectures.
86
87 Raise Exception if a list_of_requested_architectures is not supported
88 '''
89 unsupported = set(list_of_requested_architectures) - \
90 set(self.GetArchitecturesSupported())
91 if(len(unsupported) > 0):
92 errorString = (
93 "Unsupported Architecture Requested: " + " ".join(unsupported))
94 logging.critical(errorString)
95 raise Exception(errorString)
96 self.ActualArchitectures = list_of_requested_architectures
97
98 def GetWorkspaceRoot(self):
99 ''' get WorkspacePath '''
100 return CommonPlatform.WorkspaceRoot
101
102 def GetActiveScopes(self):
103 ''' return tuple containing scopes that should be active for this process '''
104
105 scopes = CommonPlatform.Scopes
106 ActualToolChainTag = shell_environment.GetBuildVars().GetValue("TOOL_CHAIN_TAG", "")
107
108 if GetHostInfo().os.upper() == "LINUX" and ActualToolChainTag.upper().startswith("GCC"):
109 if "AARCH64" in self.ActualArchitectures:
110 scopes += ("gcc_aarch64_linux",)
111 if "ARM" in self.ActualArchitectures:
112 scopes += ("gcc_arm_linux",)
113 return scopes
114
115 def FilterPackagesToTest(self, changedFilesList: list, potentialPackagesList: list) -> list:
116 ''' Filter other cases that this package should be built
117 based on changed files. This should cover things that can't
118 be detected as dependencies. '''
119 build_these_packages = []
120 possible_packages = potentialPackagesList.copy()
121 for f in changedFilesList:
122 # BaseTools files that might change the build
123 if "BaseTools" in f:
124 if os.path.splitext(f) not in [".txt", ".md"]:
125 build_these_packages = possible_packages
126 break
127
128 # if the azure pipeline platform template file changed
129 if "platform-build-run-steps.yml" in f:
130 build_these_packages = possible_packages
131 break
132
133
134 return build_these_packages
135
136 def GetPlatformDscAndConfig(self) -> tuple:
137 ''' If a platform desires to provide its DSC then Policy 4 will evaluate if
138 any of the changes will be built in the dsc.
139
140 The tuple should be (<workspace relative path to dsc file>, <input dictionary of dsc key value pairs>)
141 '''
142 return (os.path.join("ArmVirtPkg", "ArmVirtQemu.dsc"), {})
143
144
145 # ####################################################################################### #
146 # Actual Configuration for Platform Build #
147 # ####################################################################################### #
148
149
150 class PlatformBuilder(UefiBuilder, BuildSettingsManager):
151 def __init__(self):
152 UefiBuilder.__init__(self)
153
154 def AddCommandLineOptions(self, parserObj):
155 ''' Add command line options to the argparser '''
156 parserObj.add_argument('-a', "--arch", dest="build_arch", type=str, default="AARCH64",
157 help="Optional - Architecture to build. Default = AARCH64")
158
159 def RetrieveCommandLineOptions(self, args):
160 ''' Retrieve command line options from the argparser '''
161
162 shell_environment.GetBuildVars().SetValue(
163 "TARGET_ARCH", args.build_arch.upper(), "From CmdLine")
164
165 shell_environment.GetBuildVars().SetValue(
166 "ACTIVE_PLATFORM", "ArmVirtPkg/ArmVirtQemu.dsc", "From CmdLine")
167
168 def GetWorkspaceRoot(self):
169 ''' get WorkspacePath '''
170 return CommonPlatform.WorkspaceRoot
171
172 def GetPackagesPath(self):
173 ''' Return a list of workspace relative paths that should be mapped as edk2 PackagesPath '''
174 return ()
175
176 def GetActiveScopes(self):
177 ''' return tuple containing scopes that should be active for this process '''
178 scopes = CommonPlatform.Scopes
179 ActualToolChainTag = shell_environment.GetBuildVars().GetValue("TOOL_CHAIN_TAG", "")
180 Arch = shell_environment.GetBuildVars().GetValue("TARGET_ARCH", "")
181
182 if GetHostInfo().os.upper() == "LINUX" and ActualToolChainTag.upper().startswith("GCC"):
183 if "AARCH64" == Arch:
184 scopes += ("gcc_aarch64_linux",)
185 elif "ARM" == Arch:
186 scopes += ("gcc_arm_linux",)
187 return scopes
188
189 def GetName(self):
190 ''' Get the name of the repo, platform, or product being build '''
191 ''' Used for naming the log file, among others '''
192 # check the startup nsh flag and if set then rename the log file.
193 # this helps in CI so we don't overwrite the build log since running
194 # uses the stuart_build command.
195 if(shell_environment.GetBuildVars().GetValue("MAKE_STARTUP_NSH", "FALSE") == "TRUE"):
196 return "ArmVirtPkg_With_Run"
197 return "ArmVirtPkg"
198
199 def GetLoggingLevel(self, loggerType):
200 ''' Get the logging level for a given type
201 base == lowest logging level supported
202 con == Screen logging
203 txt == plain text file logging
204 md == markdown file logging
205 '''
206 return logging.DEBUG
207
208 def SetPlatformEnv(self):
209 logging.debug("PlatformBuilder SetPlatformEnv")
210 self.env.SetValue("PRODUCT_NAME", "ArmVirtQemu", "Platform Hardcoded")
211 self.env.SetValue("MAKE_STARTUP_NSH", "FALSE", "Default to false")
212 self.env.SetValue("QEMU_HEADLESS", "FALSE", "Default to false")
213 return 0
214
215 def PlatformPreBuild(self):
216 return 0
217
218 def PlatformPostBuild(self):
219 return 0
220
221 def FlashRomImage(self):
222 VirtualDrive = os.path.join(self.env.GetValue(
223 "BUILD_OUTPUT_BASE"), "VirtualDrive")
224 os.makedirs(VirtualDrive, exist_ok=True)
225 OutputPath_FV = os.path.join(
226 self.env.GetValue("BUILD_OUTPUT_BASE"), "FV")
227 Built_FV = os.path.join(OutputPath_FV, "QEMU_EFI.fd")
228
229 # pad fd to 64mb
230 with open(Built_FV, "ab") as fvfile:
231 fvfile.seek(0, os.SEEK_END)
232 additional = b'\0' * ((64 * 1024 * 1024)-fvfile.tell())
233 fvfile.write(additional)
234
235 # QEMU must be on that path
236
237 # Unique Command and Args parameters per ARCH
238 if (self.env.GetValue("TARGET_ARCH").upper() == "AARCH64"):
239 cmd = "qemu-system-aarch64"
240 args = "-M virt"
241 args += " -cpu cortex-a57" # emulate cpu
242 elif(self.env.GetValue("TARGET_ARCH").upper() == "ARM"):
243 cmd = "qemu-system-arm"
244 args = "-M virt"
245 args += " -cpu cortex-a15" # emulate cpu
246 else:
247 raise NotImplementedError()
248
249 # Common Args
250 args += " -pflash " + Built_FV # path to fw
251 args += " -m 1024" # 1gb memory
252 # turn off network
253 args += " -net none"
254 # Serial messages out
255 args += " -serial stdio"
256 # Mount disk with startup.nsh
257 args += f" -drive file=fat:rw:{VirtualDrive},format=raw,media=disk"
258
259 # Conditional Args
260 if (self.env.GetValue("QEMU_HEADLESS").upper() == "TRUE"):
261 args += " -display none" # no graphics
262
263 if (self.env.GetValue("MAKE_STARTUP_NSH").upper() == "TRUE"):
264 f = open(os.path.join(VirtualDrive, "startup.nsh"), "w")
265 f.write("BOOT SUCCESS !!! \n")
266 # add commands here
267 f.write("reset -s\n")
268 f.close()
269
270 ret = RunCmd(cmd, args)
271
272 if ret == 0xc0000005:
273 # for some reason getting a c0000005 on successful return
274 return 0
275
276 return ret