UEFI实战SlimBootloader中的构建脚本BuildLoader.py

Posted jiangwei0512

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UEFI实战SlimBootloader中的构建脚本BuildLoader.py相关的知识,希望对你有一定的参考价值。

综述

SlimBootloader构建依赖于Python脚本BuildLaoder.py,而它也依赖于额外的脚本,它们位于BootloaderCorePkg\\Tools,大致如下所示:

代码说明

这里直接列出源码,并增加说明:

#!/usr/bin/env python
## @ BuildLoader.py
# Build bootloader main script
#
# Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
#  SPDX-License-Identifier: BSD-2-Clause-Patent

##
# Import Modules
#
import os
import sys

# BootloaderCorePkg\\Tools的绝对路径,里面包含SBL需要使用的Python脚本
tool_dir = os.path.join(os.path.dirname (os.path.realpath(__file__)), 'BootloaderCorePkg', 'Tools')
# 为了不生成.pyc文件,跟功能无关
sys.dont_write_bytecode = True
# 添加到环境变量,这样SBL需要使用的Python脚本就可以直接访问了BuildUtility.py
sys.path.append (tool_dir)

import re
import errno
import shutil
import argparse
import subprocess
import multiprocessing
from   ctypes import *
# 这里的BuildUtility就来自BootloaderCorePkg\\Tools目录下的Python文件BuildUtility.py
from   BuildUtility import *

import glob


# 检查是否有BaseTools,如果没有就构建
def rebuild_basetools ():
    exe_list = 'GenFfs  GenFv  GenFw  GenSec  Lz4Compress  LzmaCompress'.split()
    ret = 0
    sblsource = os.environ['SBL_SOURCE'] # 在main()中设置,SBL根目录

    if os.name == 'posix': # Linux
        if not check_files_exist (exe_list, os.path.join(sblsource, 'BaseTools', 'Source', 'C', 'bin')):
            ret = run_process (['make', '-C', 'BaseTools'])

    elif os.name == 'nt': # Windows
        # 如果没有构建工具(就是exe_list定义的工具),就创建
        if not check_files_exist (exe_list, os.path.join(sblsource, 'BaseTools', 'Bin', 'Win32'), '.exe'):
            print ("Could not find pre-built BaseTools binaries, try to rebuild BaseTools ...")
            ret = run_process (['BaseTools\\\\toolsetup.bat', 'forcerebuild'])

    if ret:
        print ("Build BaseTools failed, please check required build environment and utilities !")
        sys.exit(1)


# 创建Conf目录及其下文件
def create_conf (workspace, sbl_source):
    # create conf and build folder if not exist
    workspace = os.environ['WORKSPACE'] # 也在main()下设置,值就是跟'SBL_SOURCE'一样,都是SBL根目录
    if not os.path.exists(os.path.join(workspace, 'Conf')):
        os.makedirs(os.path.join(workspace, 'Conf')) # 创建Conf目录
    for name in ['target', 'tools_def', 'build_rule']: # 拷贝基本配置文件
        txt_file = os.path.join(workspace, 'Conf/%s.txt' % name)
        if not os.path.exists(txt_file):
            shutil.copy (
                os.path.join(sbl_source, 'BaseTools/Conf/%s.template' % name),
                os.path.join(workspace, 'Conf/%s.txt' % name))


# 设置环境变量
#   PATH
#   PYTHONPATH
#   EDK_TOOLS_PATH
#   BASE_TOOLS_PATH
#   CONF_PATH
#   SBL_KEY_DIR
def prep_env (toolchain_preferred = ''):
    sblsource = os.environ['SBL_SOURCE']
    os.chdir(sblsource)

    # Verify toolchains first
    # 检测各类工具的版本是否满足要求
    # 大致检测的内容:
    # Checking Toolchain Versions...
    # - C:\\Python36\\python.exe: Version 3.6.8 (>= 3.6.0) [PASS]
    # - C:\\Openssl\\openssl.exe: Version 1.1.1h (>= 1.1.0g) [PASS]
    # - C:\\Nasm\\nasm: Version 2.13.03 (>= 2.12.02) [PASS]
    # - C:\\ASL\\iasl: Version 20210930 (>= 20160422) [PASS]
    # - git: Version 2.21.0. (>= 2.20.0) [PASS]
    # - vs: Version 2019 (>= 2015) [PASS]
    verify_toolchains(toolchain_preferred)

    # Update Environment vars
    if os.name == 'nt':
        os.environ['PATH'] = os.environ['PATH'] + ';' + os.path.join(sblsource, 'BaseTools', 'Bin', 'Win32')
        os.environ['PATH'] = os.environ['PATH'] + ';' + os.path.join(sblsource, 'BaseTools', 'BinWrappers', 'WindowsLike')
        os.environ['PYTHONPATH'] = os.path.join(sblsource, 'BaseTools', 'Source', 'Python')
    else:
        os.environ['PATH'] = os.environ['PATH'] + ':' + os.path.join(sblsource, 'BaseTools', 'BinWrappers', 'PosixLike')

    os.environ['EDK_TOOLS_PATH'] = os.path.join(sblsource, 'BaseTools')
    os.environ['BASE_TOOLS_PATH'] = os.path.join(sblsource, 'BaseTools')
    os.environ['CONF_PATH'] = os.path.join(os.environ['WORKSPACE'], 'Conf')

    if 'SBL_KEY_DIR' not in os.environ:
        os.environ['SBL_KEY_DIR'] = os.path.join(sblsource, '..', 'SblKeys')

    create_conf (os.environ['WORKSPACE'], sblsource) # 创建Conf目录

    # Check if BaseTools has been compiled
    rebuild_basetools () # 生成构建工具


# 返回所有的BoardConfig*.py文件(比如BoardConfig.py和BoardConfigOverride.py),并放到board_cfgs中
# 注意返回的是绝对路径
# 下面是一种结果:
# [
# 'F:\\\\Gitee\\\\slimbootloader\\\\Platform\\\\ApollolakeBoardPkg\\\\BoardConfig.py',
# 'F:\\\\Gitee\\\\slimbootloader\\\\Platform\\\\CoffeelakeBoardPkg\\\\BoardConfig.py',
# 'F:\\\\Gitee\\\\slimbootloader\\\\Platform\\\\CometlakeBoardPkg\\\\BoardConfig.py',
# 'F:\\\\Gitee\\\\slimbootloader\\\\Platform\\\\CometlakevBoardPkg\\\\BoardConfig.py',
# 'F:\\\\Gitee\\\\slimbootloader\\\\Platform\\\\ElkhartlakeBoardPkg\\\\BoardConfig.py',
# 'F:\\\\Gitee\\\\slimbootloader\\\\Platform\\\\QemuBoardPkg\\\\BoardConfig.py',
# 'F:\\\\Gitee\\\\slimbootloader\\\\Platform\\\\QemuBoardPkg\\\\BoardConfigOverride.py',
# 'F:\\\\Gitee\\\\slimbootloader\\\\Platform\\\\TigerlakeBoardPkg\\\\BoardConfig.py'
# ]
def get_board_config_file (check_dir, board_cfgs):
    # 指定platform_dir为根目录下的Platform目录,正常情况下,SBL根目录下就有一个Platform目录
    platform_dir = os.path.join (check_dir, 'Platform')
    if not os.path.isdir (platform_dir):
        if os.path.basename(check_dir) == 'Platform':
            platform_dir = check_dir
        else:
            return
    # 指定Platform目录下支持的所有平台
    board_pkgs = os.listdir(platform_dir)
    for pkg in board_pkgs:
        # Allow files starting with 'BoardConfig' only
        for cfgfile in glob.glob(os.path.join(platform_dir, pkg, 'BoardConfig*.py')):
            # board_cfgs指定所有平台下的BoardConfig.py文件
            board_cfgs.append(cfgfile)


# 单板基本配置项,会写到Platform.dsc,并最终在dsc中使用
class BaseBoard(object):
    def __init__(self, *args, **kwargs):

        # NOTE: Variables starting with '_' will not be exported to Platform.dsc


        self.LOGO_FILE              = 'Platform/CommonBoardPkg/Logo/Logo.bmp'

        self._RSA_SIGN_TYPE          = 'RSA2048'
        self._SIGN_HASH              = 'SHA2_256'
        self.SIGN_HASH_TYPE          = HASH_TYPE_VALUE[self._SIGN_HASH]
        self._SIGNING_SCHEME         = 'RSA_PSS'

        # Default key dir is set by SBL_KEY_DIR. _KEY_DIR is set to NULL.
        self._KEY_DIR = ''
        self._MASTER_PRIVATE_KEY    = 'KEY_ID_MASTER' + '_' + self._RSA_SIGN_TYPE
        self._CFGDATA_PRIVATE_KEY   = 'KEY_ID_CFGDATA' + '_' + self._RSA_SIGN_TYPE
        self._CONTAINER_PRIVATE_KEY = 'KEY_ID_CONTAINER' + '_' + self._RSA_SIGN_TYPE

        self.KEY_GEN                 = 0

        self.VERINFO_IMAGE_ID       = 'SB_???? '
        self.VERINFO_PROJ_ID        = 1
        self.VERINFO_CORE_MAJOR_VER = 1
        self.VERINFO_CORE_MINOR_VER = 0

        self.VERINFO_PROJ_MAJOR_VER = 0
        self.VERINFO_PROJ_MINOR_VER = 1
        self.VERINFO_SVN            = 1
        self.VERINFO_BUILD_DATE     = '01/01/2018'

        self.LOWEST_SUPPORTED_FW_VER = 1

        self.FLASH_BLOCK_SIZE       = 0x1000
        self.FLASH_LAYOUT_START     = 0x100000000
        self.FLASH_BASE             = 0
        self.FLASH_SIZE             = 0

        self.PCI_EXPRESS_BASE       = 0xE0000000
        self.ACPI_PM_TIMER_BASE     = 0x0408
        self.USB_KB_POLLING_TIMEOUT = 1

        self.VERIFIED_BOOT_STAGE_1B   = 0x0
        self.BOOT_MEDIA_SUPPORT_MASK  = 0xFFFFFFFF
        self.FILE_SYSTEM_SUPPORT_MASK = 0x00000003
        self.DEBUG_OUTPUT_DEVICE_MASK = 0x00000003
        self.DEBUG_PORT_NUMBER        = 0x00000002
        self.CONSOLE_IN_DEVICE_MASK   = 0x00000001
        self.CONSOLE_OUT_DEVICE_MASK  = 0x00000001

        self.HAVE_VBT_BIN          = 0
        self.HAVE_FIT_TABLE        = 0
        self.HAVE_VERIFIED_BOOT    = 0
        self.HAVE_MEASURED_BOOT    = 0
        self.HAVE_FSP_BIN          = 1
        self.HAVE_ACPI_TABLE       = 1
        self.HAVE_PSD_TABLE        = 0
        self.HAVE_SEED_LIST        = 0

        self.FIT_ENTRY_MAX_NUM     = 10

        self.ENABLE_PCI_ENUM       = 1
        self.ENABLE_SMP_INIT       = 1
        self.ENABLE_FSP_LOAD_IMAGE = 0
        self.ENABLE_SPLASH         = 0
        self.ENABLE_FRAMEBUFFER_INIT = 0
        self.ENABLE_PRE_OS_CHECKER = 0
        self.ENABLE_CRYPTO_SHA_OPT  = IPP_CRYPTO_OPTIMIZATION_MASK['SHA256_V8']
        self.ENABLE_FWU            = 0
        self.ENABLE_SOURCE_DEBUG   = 0
        self.ENABLE_GRUB_CONFIG    = 0
        self.ENABLE_SMBios         = 0
        self.ENABLE_LINUX_PAYLOAD  = 0
        self.ENABLE_CONTAINER_BOOT = 1
        self.ENABLE_CSME_UPDATE    = 0
        self.ENABLE_EMMC_HS400     = 1
        self.ENABLE_DMA_PROTECTION = 0
        self.ENABLE_MULTI_USB_BOOT_DEV = 0
        self.ENABLE_SBL_SETUP      = 0
        self.ENABLE_PAYLOD_MODULE  = 0
        self.ENABLE_FAST_BOOT      = 0
        self.ENABLE_LEGACY_EF_SEG  = 1
        # 0: Disable  1: Enable  2: Auto (disable for UEFI payload, enable for others)
        self.ENABLE_SMM_REBASE     = 0

        self.SUPPORT_ARI           = 0
        self.SUPPORT_SR_IOV        = 0
        self.SUPPORT_X2APIC        = 0

        self.BUILD_CSME_UPDATE_DRIVER    = 0

        self.CPU_MAX_LOGICAL_PROCESSOR_NUMBER = 16

        self.ACM_SIZE              = 0
        self.DIAGNOSTICACM_SIZE    = 0
        self.UCODE_SIZE            = 0
        self.CFGDATA_SIZE          = 0
        self.MRCDATA_SIZE          = 0
        self.VARIABLE_SIZE         = 0
        self.UEFI_VARIABLE_SIZE    = 0
        self.FWUPDATE_SIZE         = 0

        self.SPI_IAS1_SIZE         = 0
        self.SPI_IAS2_SIZE         = 0

        self.KM_SIZE               = 0x1000 # valid only if ACM_SIZE > 0
        self.BPM_SIZE              = 0x1000 # valid only if ACM_SIZE > 0
        self.CFG_DATABASE_SIZE     = 0

        self.FSP_M_STACK_TOP       = 0
        self.STAGE1A_XIP           = 1
        self.STAGE1B_XIP           = 1
        self.STAGE1_STACK_BASE_OFFSET = 0
        self.STAGE2_XIP            = 0
        self.STAGE2_LOAD_HIGH      = 1
        self.PAYLOAD_LOAD_HIGH     = 1
        self.PAYLOAD_EXE_BASE      = 0x00800000

        #     0: Direct access from flash
        # other: Load image into memory address
        self.PAYLOAD_LOAD_BASE     = 0
        self.FWUPDATE_LOAD_BASE    = 0

        # OS Loader FD/FV sizes
        self.OS_LOADER_FD_SIZE     = 0x0004E000

        self.OS_LOADER_FD_NUMBLK   = self.OS_LOADER_FD_SIZE // self.FLASH_BLOCK_SIZE

        self.PLD_HEAP_SIZE         = 0x02000000
        self.PLD_STACK_SIZE        = 0x00010000
        self.PLD_RSVD_MEM_SIZE     = 0x00004000

        # These memory sizes need to be page aligned
        self.LOADER_RSVD_MEM_SIZE         = 0x0038C000
        self.LOADER_ACPI_NVS_MEM_SIZE     = 0x00008000
        self.LOADER_ACPI_RECLAIM_MEM_SIZE = 0x00068000

        self.CFGDATA_REGION_TYPE   = FLASH_REGION_TYPE.BIOS

        self.RELEASE_MODE          = 0
        self.NO_OPT_MODE           = 0
        self.FSPDEBUG_MODE         = 0
        self.MIN_FSP_REVISION      = 0
        self.FSP_IMAGE_ID          = ''

        self.TOP_SWAP_SIZE         = 0
        self.REDUNDANT_SIZE        = 0

        self._PAYLOAD_NAME         = ''
        self._FSP_PATH_NAME        = ''
        self._EXTRA_INC_PATH       = []

        self._PLATFORM_ID          = None
        self._MULTI_VBT_FILE       = {}
        self._CFGDATA_INT_FILE     = []
        self._CFGDATA_EXT_FILE     = []

        self.IPP_HASH_LIB_SUPPORTED_MASK   = IPP_CRYPTO_ALG_MASK[self._SIGN_HASH]

        self.HASH_STORE_SIZE       = 0x400  #Hash store size to be allocated in bootloader

        self.PCI_MEM64_BASE        = 0
        self.BUILD_ARCH            = 'IA32'
        self.KEYH_SVN              = 0
        self.CFGDATA_SVN           = 0

        for key, value in list(kwargs.items()):
            setattr(self, '%s' % key, value)


# 将构建操作作为一个类来处理
class Build(object):
    # 构造函数,初始化使用Build(board),board的类型是BaseBoard及其子类
    def __init__(self, board):
        self._toolchain                    = os.environ['TOOL_CHAIN'] # 在BuildUtility.py中设置
        self._workspace                    = os.environ['WORKSPACE']
        self._board                        = board
        self._image                        = "SlimBootloader.bin"
        self._arch                         = board.BUILD_ARCH
        self._target                       = 'RELEASE' if board.RELEASE_MODE  else 'NOOPT' if board.NO_OPT_MODE else 'DEBUG'
        self._fsp_basename                 = 'FspDbg'  if board.FSPDEBUG_MODE else 'FspRel'
        self._fv_dir                       = os.path.join(self._workspace, 'Build', 'BootloaderCorePkg', '%s_%s' % (self._target, self._toolchain), 'FV')
        self._key_dir                      = self._board._KEY_DIR
        self._img_list                     = board.GetImageLayout()
        # pld就是Payload,如果没有指定payload参数,则默认的值是OsLoader.efi
        self._pld_list                     = get_payload_list (board._PAYLOAD_NAME.split(';'))
        self._comp_list                    = []
        self._region_list                  = []

        # enforce feature configs rules
        if self._board.ENABLE_SBL_SETUP:
            self._board.ENABLE_PAYLOD_MODULE = 1
        # Python可以增加新的成员在类实例中
        if not hasattr(self._board, 'MICROCODE_INF_FILE'):
            self._board.MICROCODE_INF_FILE  = 'Silicon/%s/Microcode/Microcode.inf' % self._board.SILICON_PKG_NAME
        if not hasattr(self._board, 'ACPI_TABLE_INF_FILE'):
            self._board.ACPI_TABLE_INF_FILE = 'Platform/%s/AcpiTables/AcpiTables.inf' % self._board.BOARD_PKG_NAME

        for stage in ['1A', '1B', '2']:
            soc_inf = 'SOC_INIT_STAGE%s_LIB_INF_FILE' % stage
            if not hasattr(self._board, soc_inf):
                soc_init_lib = 'Silicon/%s/Library/Stage%sSocInitLib/Stage%sSocInitLib.inf' % (self._board.SILICON_PKG_NAME, stage, stage)
                setattr(self._board, 'SOC_INIT_STAGE%s_LIB_INF_FILE' % stage, soc_init_lib)
            brd_inf = 'BRD_INIT_STAGE%s_LIB_INF_FILE' % stage
            if not hasattr(self._board, brd_inf):
                brd_init_lib = 'Platform/%s/Library/Stage%sBoardInitLib/Stage%sBoardInitLib.inf' % (self._board.BOARD_PKG_NAME, stage, stage)
                setattr(self._board, 'BRD_INIT_STAGE%s_LIB_INF_FILE' % stage, brd_init_lib)

        if not hasattr(self._board, 'SOC_FWU_LIB_INF_FILE'):
            self._board.SOC_FWU_LIB_INF_FILE = 'Silicon/%s/Library/FirmwareUpdateLib/FirmwareUpdateLib.inf' % self._board.SILICON_PKG_NAME

    # BoardConfig.py中如果有定义PlatformBuildHook函数,这会执行
    def board_build_hook (self, phase):
        if getattr(self._board, "PlatformBuildHook", None):
            self._board.PlatformBuildHook (self, phase)

    def update_fit_table (self):

        if not self._board.HAVE_FIT_TABLE:
            return

        print('Updating FIT')
        # self._fv_dir就是Build\\BootloaderCorePkg\\DEBUG_VS2019\\FV(根据编译器可能会有不同)
        # self._image就是SlimBootloader.bin
        img_file = os.path.join (self._fv_dir, self._image)
        fi = open(img_file,'rb')
        rom = bytearray(fi.read()) # 得到字节数组
        fi.close()

        # Find FIT pointer @ 0xFFFFFFC0
        # FIT_ENTRY.FIT_OFFSET来自BootloaderCorePkg\\Tools\\IfwiUtility.py,值是-40
        fit_address = c_uint32.from_buffer(rom, len(rom) + FIT_ENTRY.FIT_OFFSET)
        print('  FIT Address: 0x%08X' % fit_address.value)

        # 如果支持ACM,则地址必须是64字节对齐的
        if self._board.ACM_SIZE > 0:
            # Check FIT address alignment for 64 bytes if ACM is used
            # because BIOS IBB segments base/size require 64 bytes alignment.
            if fit_address.value & ~0x3F != fit_address.value:
                raise Exception ('  FIT address (0x%08X) is not 64-byte aligned' % fit_address.value以上是关于UEFI实战SlimBootloader中的构建脚本BuildLoader.py的主要内容,如果未能解决你的问题,请参考以下文章

UEFI实战SlimBootloader定制化

UEFI实战SlimBootloader集成UEFI Payload

UEFI实战SlimBootloader集成UEFI Payload

UEFI实战SlimBootloader使用

UEFI实战SlimBootloader中调用FSP

UEFI实战SlimBootloader中调用FSP