编译产生 BIOS ROM的最后一个步骤是将 FV 打包,那么这个操作是在哪里?带着这个问题,以 OVMF 的 PKG 为例进行研究。
我们平时编译使用的是 BaseTools\Bin\Win32下面的 build.exe ,这个文件是使用 Python 转 EXE工具生成的。如果想研究 Build.exe 具体的代码,可以将 build.exe 改名或者删除,然后保证当前 path 中含有BaseTools\BinWrappers\WindowsLike 路径,这样调用 Built 时会直接使用目录下的 Build.bat,该批处理内容如下:
@setlocal
@set ToolName=%~n0%
@%PYTHON_HOME%\python.exe %BASE_TOOLS_PATH%\Source\Python\%ToolName%\%ToolName%.py %*
如果你调用 build就会使用 Python.exe 来执行BaseTools\Source\Python\build\build.py。特别提醒,我实验发现 Python38 会出现如下的错误:
except BaseException, X:
^
SyntaxError: invalid syntax
修正方法是更换为 Python27 的版本(他们可以共存)。另外,这个问题也可能是我使用的 EDK2 版本的问题(我实验环境是EDK2201911).
代码入口在 main中,可以通过加入下面2条语句做一个标记:
print("www.lab-z.com\n")
subprocess.call("pause",shell=True)
添加在代码中入口位置
## Tool entrance method
#
# This method mainly dispatch specific methods per the command line options.
# If no error found, return zero value so the caller of this tool can know
# if it's executed successfully or not.
#
# @retval 0 Tool was successful
# @retval 1 Tool failed
#
def Main():
测试结果:

代码中MyBuild.Launch()是具体执行 build 动作的地方:
MyBuild = Build(Target, Workspace, Option)
GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList)
if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)):
MyBuild.Launch()
实验确定对应代码:
## Launch the module or platform build
#
def Launch(self):
if not self.ModuleFile:
if not self.SpawnMode or self.Target not in ["", "all"]:
self.SpawnMode = False
self._BuildPlatform()
else:
self._MultiThreadBuildPlatform()
self.CreateGuidedSectionToolsFile()
else:
self.SpawnMode = False
self._BuildModule()
self._MultiThreadBuildPlatform() 这里会完成所有的动作.这个函数在同一个文件中:
## Build a platform in multi-thread mode
#
def _MultiThreadBuildPlatform(self):
SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False)
我们的目标是找到最后将 FV 打包的过程,在代码中下面的位置加入 Pause 可以正常停下来,所以确定这个是我们目标动作的位置。
if self.Fdf:
print("www.lab-z.com\n")
subprocess.call("pause",shell=True)
#
# Generate FD image if there's a FDF file found
#
GenFdsStart = time.time()
LaunchCommand(Wa.GenFdsCommand, os.getcwd())
#
# Create MAP file for all platform FVs after GenFds.
#
self._CollectFvMapBuffer(MapBuffer, Wa, ModuleList)
self.GenFdsTime += int(round((time.time() - GenFdsStart)))
#
# Save MAP buffer into MAP file.
#
self._SaveMapFile(MapBuffer, Wa)
代码中加入下面两句输出具体调用的命令:
print("[%s]\n" % Wa.GenFdsCommand)
print("[%s]\n" % os.getcwd())
subprocess.call("pause",shell=True)

测试,在编译环境下输入下面的 command, 可以实现生成 OVMF.fd:
GenFds -f c:\buildbs\i2c\OvmfPkg\OvmfPkgX64.fdf --conf=c:\buildbs\i2c\conf -o c:\buildbs\i2c\Build\OvmfX64\DEBUG_VS2015x86 -t VS2015x86 -b DEBUG -p c:\buildbs\i2c\OvmfPkg\OvmfPkgX64.dsc -a X64 -D "EFI_SOURCE=c:\\buildbs\\i2c\\edkcompatibilitypkg" -D "EDK_SOURCE=c:\\buildbs\\i2c\\edkcompatibilitypkg" -D "TOOL_CHAIN_TAG=VS2015x86" -D "TOOLCHAIN=VS2015x86" -D "TARGET=DEBUG" -D "FAMILY=MSFT" -D "WORKSPACE=c:\\buildbs\\i2c" -D "EDK_TOOLS_PATH=c:\\buildbs\\i2c\\basetools" -D "ARCH=X64" -D "ECP_SOURCE=c:\\buildbs\\i2c\\edkcompatibilitypkg"
结论:build 过程中的最后一段是调用 GenFds 来生成 BIOS 的 FD (或者叫做 ROM)文件。