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 Payload