]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/PlatformCI/PlatformBuildLib.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / PlatformCI / PlatformBuildLib.py
CommitLineData
61be49e0
GH
1# @file\r
2# Script to Build OVMF UEFI firmware\r
3#\r
4# Copyright (c) Microsoft Corporation.\r
5# SPDX-License-Identifier: BSD-2-Clause-Patent\r
6##\r
7import os\r
8import logging\r
9import io\r
10\r
11from edk2toolext.environment import shell_environment\r
12from edk2toolext.environment.uefi_build import UefiBuilder\r
13from edk2toolext.invocables.edk2_platform_build import BuildSettingsManager\r
14from edk2toolext.invocables.edk2_setup import SetupSettingsManager, RequiredSubmodule\r
15from edk2toolext.invocables.edk2_update import UpdateSettingsManager\r
16from edk2toolext.invocables.edk2_pr_eval import PrEvalSettingsManager\r
17from edk2toollib.utility_functions import RunCmd\r
18\r
19\r
20 # ####################################################################################### #\r
21 # Configuration for Update & Setup #\r
22 # ####################################################################################### #\r
23class SettingsManager(UpdateSettingsManager, SetupSettingsManager, PrEvalSettingsManager):\r
24\r
25 def GetPackagesSupported(self):\r
26 ''' return iterable of edk2 packages supported by this build.\r
27 These should be edk2 workspace relative paths '''\r
28 return CommonPlatform.PackagesSupported\r
29\r
30 def GetArchitecturesSupported(self):\r
31 ''' return iterable of edk2 architectures supported by this build '''\r
32 return CommonPlatform.ArchSupported\r
33\r
34 def GetTargetsSupported(self):\r
35 ''' return iterable of edk2 target tags supported by this build '''\r
36 return CommonPlatform.TargetsSupported\r
37\r
38 def GetRequiredSubmodules(self):\r
39 ''' return iterable containing RequiredSubmodule objects.\r
40 If no RequiredSubmodules return an empty iterable\r
41 '''\r
42 rs = []\r
43\r
44 # intentionally declare this one with recursive false to avoid overhead\r
45 rs.append(RequiredSubmodule(\r
46 "CryptoPkg/Library/OpensslLib/openssl", False))\r
47\r
48 # To avoid maintenance of this file for every new submodule\r
49 # lets just parse the .gitmodules and add each if not already in list.\r
50 # The GetRequiredSubmodules is designed to allow a build to optimize\r
51 # the desired submodules but it isn't necessary for this repository.\r
52 result = io.StringIO()\r
53 ret = RunCmd("git", "config --file .gitmodules --get-regexp path", workingdir=self.GetWorkspaceRoot(), outstream=result)\r
54 # Cmd output is expected to look like:\r
55 # submodule.CryptoPkg/Library/OpensslLib/openssl.path CryptoPkg/Library/OpensslLib/openssl\r
56 # submodule.SoftFloat.path ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3\r
57 if ret == 0:\r
58 for line in result.getvalue().splitlines():\r
59 _, _, path = line.partition(" ")\r
60 if path is not None:\r
61 if path not in [x.path for x in rs]:\r
62 rs.append(RequiredSubmodule(path, True)) # add it with recursive since we don't know\r
63 return rs\r
64\r
65 def SetArchitectures(self, list_of_requested_architectures):\r
66 ''' Confirm the requests architecture list is valid and configure SettingsManager\r
67 to run only the requested architectures.\r
68\r
69 Raise Exception if a list_of_requested_architectures is not supported\r
70 '''\r
71 unsupported = set(list_of_requested_architectures) - set(self.GetArchitecturesSupported())\r
72 if(len(unsupported) > 0):\r
73 errorString = ( "Unsupported Architecture Requested: " + " ".join(unsupported))\r
74 logging.critical( errorString )\r
75 raise Exception( errorString )\r
76 self.ActualArchitectures = list_of_requested_architectures\r
77\r
78 def GetWorkspaceRoot(self):\r
79 ''' get WorkspacePath '''\r
80 return CommonPlatform.WorkspaceRoot\r
81\r
82 def GetActiveScopes(self):\r
83 ''' return tuple containing scopes that should be active for this process '''\r
84 return CommonPlatform.Scopes\r
85\r
86 def FilterPackagesToTest(self, changedFilesList: list, potentialPackagesList: list) -> list:\r
87 ''' Filter other cases that this package should be built\r
88 based on changed files. This should cover things that can't\r
89 be detected as dependencies. '''\r
90 build_these_packages = []\r
91 possible_packages = potentialPackagesList.copy()\r
92 for f in changedFilesList:\r
93 # BaseTools files that might change the build\r
94 if "BaseTools" in f:\r
95 if os.path.splitext(f) not in [".txt", ".md"]:\r
96 build_these_packages = possible_packages\r
97 break\r
98\r
99 # if the azure pipeline platform template file changed\r
100 if "platform-build-run-steps.yml" in f:\r
101 build_these_packages = possible_packages\r
102 break\r
103\r
104 return build_these_packages\r
105\r
106 def GetPlatformDscAndConfig(self) -> tuple:\r
107 ''' If a platform desires to provide its DSC then Policy 4 will evaluate if\r
108 any of the changes will be built in the dsc.\r
109\r
110 The tuple should be (<workspace relative path to dsc file>, <input dictionary of dsc key value pairs>)\r
111 '''\r
112 dsc = CommonPlatform.GetDscName(",".join(self.ActualArchitectures))\r
113 return (f"OvmfPkg/{dsc}", {})\r
114\r
115\r
116 # ####################################################################################### #\r
117 # Actual Configuration for Platform Build #\r
118 # ####################################################################################### #\r
119class PlatformBuilder( UefiBuilder, BuildSettingsManager):\r
120 def __init__(self):\r
121 UefiBuilder.__init__(self)\r
122\r
123 def AddCommandLineOptions(self, parserObj):\r
124 ''' Add command line options to the argparser '''\r
125 parserObj.add_argument('-a', "--arch", dest="build_arch", type=str, default="IA32,X64",\r
126 help="Optional - CSV of architecture to build. IA32 will use IA32 for Pei & Dxe. "\r
127 "X64 will use X64 for both PEI and DXE. IA32,X64 will use IA32 for PEI and "\r
128 "X64 for DXE. default is IA32,X64")\r
129\r
130 def RetrieveCommandLineOptions(self, args):\r
131 ''' Retrieve command line options from the argparser '''\r
132\r
133 shell_environment.GetBuildVars().SetValue("TARGET_ARCH"," ".join(args.build_arch.upper().split(",")), "From CmdLine")\r
134 dsc = CommonPlatform.GetDscName(args.build_arch)\r
135 shell_environment.GetBuildVars().SetValue("ACTIVE_PLATFORM", f"OvmfPkg/{dsc}", "From CmdLine")\r
136\r
137 def GetWorkspaceRoot(self):\r
138 ''' get WorkspacePath '''\r
139 return CommonPlatform.WorkspaceRoot\r
140\r
141 def GetPackagesPath(self):\r
142 ''' Return a list of workspace relative paths that should be mapped as edk2 PackagesPath '''\r
143 return ()\r
144\r
145 def GetActiveScopes(self):\r
146 ''' return tuple containing scopes that should be active for this process '''\r
147 return CommonPlatform.Scopes\r
148\r
149 def GetName(self):\r
150 ''' Get the name of the repo, platform, or product being build '''\r
151 ''' Used for naming the log file, among others '''\r
152 # check the startup nsh flag and if set then rename the log file.\r
153 # this helps in CI so we don't overwrite the build log since running\r
154 # uses the stuart_build command.\r
155 if(shell_environment.GetBuildVars().GetValue("MAKE_STARTUP_NSH", "FALSE") == "TRUE"):\r
156 return "OvmfPkg_With_Run"\r
157 return "OvmfPkg"\r
158\r
159 def GetLoggingLevel(self, loggerType):\r
160 ''' Get the logging level for a given type\r
161 base == lowest logging level supported\r
162 con == Screen logging\r
163 txt == plain text file logging\r
164 md == markdown file logging\r
165 '''\r
166 return logging.DEBUG\r
167\r
168 def SetPlatformEnv(self):\r
169 logging.debug("PlatformBuilder SetPlatformEnv")\r
170 self.env.SetValue("PRODUCT_NAME", "OVMF", "Platform Hardcoded")\r
171 self.env.SetValue("MAKE_STARTUP_NSH", "FALSE", "Default to false")\r
172 self.env.SetValue("QEMU_HEADLESS", "FALSE", "Default to false")\r
3beb8c96 173 self.env.SetValue("QEMU_CPUHP_QUIRK", "FALSE", "Default to false")\r
61be49e0
GH
174 return 0\r
175\r
176 def PlatformPreBuild(self):\r
177 return 0\r
178\r
179 def PlatformPostBuild(self):\r
180 return 0\r
181\r
182 def FlashRomImage(self):\r
183 VirtualDrive = os.path.join(self.env.GetValue("BUILD_OUTPUT_BASE"), "VirtualDrive")\r
184 os.makedirs(VirtualDrive, exist_ok=True)\r
185 OutputPath_FV = os.path.join(self.env.GetValue("BUILD_OUTPUT_BASE"), "FV")\r
186\r
21ee3794
GH
187 if (self.env.GetValue("QEMU_SKIP") and\r
188 self.env.GetValue("QEMU_SKIP").upper() == "TRUE"):\r
189 logging.info("skipping qemu boot test")\r
190 return 0\r
191\r
61be49e0
GH
192 #\r
193 # QEMU must be on the path\r
194 #\r
195 cmd = "qemu-system-x86_64"\r
196 args = "-debugcon stdio" # write messages to stdio\r
197 args += " -global isa-debugcon.iobase=0x402" # debug messages out thru virtual io port\r
198 args += " -net none" # turn off network\r
199 args += f" -drive file=fat:rw:{VirtualDrive},format=raw,media=disk" # Mount disk with startup.nsh\r
200\r
201 if (self.env.GetValue("QEMU_HEADLESS").upper() == "TRUE"):\r
202 args += " -display none" # no graphics\r
203\r
204 if (self.env.GetBuildValue("SMM_REQUIRE") == "1"):\r
205 args += " -machine q35,smm=on" #,accel=(tcg|kvm)"\r
206 #args += " -m ..."\r
207 #args += " -smp ..."\r
208 args += " -global driver=cfi.pflash01,property=secure,value=on"\r
209 args += " -drive if=pflash,format=raw,unit=0,file=" + os.path.join(OutputPath_FV, "OVMF_CODE.fd") + ",readonly=on"\r
210 args += " -drive if=pflash,format=raw,unit=1,file=" + os.path.join(OutputPath_FV, "OVMF_VARS.fd")\r
211 else:\r
212 args += " -pflash " + os.path.join(OutputPath_FV, "OVMF.fd") # path to firmware\r
213\r
214\r
3beb8c96
AB
215 ###\r
216 ### NOTE This is a temporary workaround to allow platform CI to cope with\r
217 ### a QEMU bug in the CPU hotplug code. Once the CI environment has\r
218 ### been updated to carry a fixed version of QEMU, this can be\r
219 ### removed again\r
220 ###\r
221 ### Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=4250\r
222 ###\r
223 if (self.env.GetValue("QEMU_CPUHP_QUIRK").upper() == "TRUE"):\r
224 args += " -fw_cfg name=opt/org.tianocore/X-Cpuhp-Bugcheck-Override,string=yes"\r
225\r
61be49e0
GH
226 if (self.env.GetValue("MAKE_STARTUP_NSH").upper() == "TRUE"):\r
227 f = open(os.path.join(VirtualDrive, "startup.nsh"), "w")\r
228 f.write("BOOT SUCCESS !!! \n")\r
229 ## add commands here\r
230 f.write("reset -s\n")\r
231 f.close()\r
232\r
233 ret = RunCmd(cmd, args)\r
234\r
235 if ret == 0xc0000005:\r
236 #for some reason getting a c0000005 on successful return\r
237 return 0\r
238\r
239 return ret\r