Step to UEFI (226)EDK2 生成 ROM 最后的打包动作(上)

编译产生 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)文件。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注