Build System

SBL chooses EDK II build system to compile and build SBL image. EDK II build infrastructure provides a flexible framework supporting different platforms and extensive configuration capabilities.

It supports many tools chains including GCC on Linux and Visual Studio on Windows.

This choice also comes with two benefits:

  • EDK II build tool is familiar to many UEFI/BIOS developers

  • Open source EDK II libraries can be ported with smaller effort

Build Process

SBL build process is implemented in top level build script BuildLoader.py. The following diagram illustrates main steps:

digraph buildsteps {
   bgcolor="transparent";
     compound=true;
     node [fontsize=10, shape=rectangle];
     edge [fontsize=10];

     subgraph cluster_steps {
       label="Build Process"; fontsize=11;
       style="filled,rounded"; color="#F0F0F0";

       "Generate Build Configuration" -> "Generate Configuration Data" -> "Invoke EDK II Build Tools \nto Generate Executables" -> "Assemble Generated Files Into \nOne or More Output Images";

     }
}

The generated files are located in Build/ directory.

The SBL image, configuration data, and (generated) helper scripts, are located in Outputs/ directory.

Note

To assist debugging, the build process also generates SlimBootloader.txt file which contains flash layout details for each component in SBL image.

Pre Build Customization

SBL build system provides build time customization. Before the build, one can modify the configuration file Platform/<Platform_Foo>/BoardConfig.py based on requirement, image footprint, or hardware features etc.

Prebuild process determines the build time configuration by generating multiple files, among those are:

File

Description

Platform.dsc

Finalized platform configuration based on BoardConfig.py

ConfigDataStruct.h

C header file for configuration data structure based on *.yaml file

ConfigDataBlob.h

C file for Internal configuration data with default values

See Customize Build for more details.

Build SBL

SBL master build script BuildLoader.py provides many options to compile images. To get help:

python BuildLoader.py build -h

Set env variable for SBL Key directory:

$set SBL_KEY_DIR=$(SBL_ROOT)\..\SblKeys\

Build SBL for a supported platform:

python BuildLoader.py build <platform_name>

Clean up files generated during build process:

python BuildLoader.py clean

Final SBL image(s) should be generated under Outputs/<platform_name> directory

See Build Tool for more details.

Build Details per Stage

Slim Bootloader is built in stages and more information on each stage is given below.

  • Stage 1A:

    • Packaged As: FD containing Stage1A FV, and FSP-T binary as a FILE

    • Stage 1A FV:

      • Contains ResetVector, VerInfo, FlashMap, FitTable, HashStore, PEIPcdDataBase, and Stage1A PEIM

      • Stage 1A contains a module called VTF (Volume Top File) which is placed at the top within the Stage 1A FV. The VTF contains the reset vector code and hence the VTF needs to be placed at an appropriate address so that the reset vector code in the the Vtf0 file (Identified by the GUID 1BA0062E-C779-4582-8566-336AE8F78F09) aligns with the reset vector of Intel x86 architecture.

        The entry point for the Stage1A module within the Stage1A FV (_ModuleEntryPoint) is placed as the first DWORD of the built FV. The reset vector code from the Vtf0 jumps to this address and continues from the _ModuleEntryPoint defined in SecEntry.nasm.


  • Stage 1B:

    • Packaged As: FD containing Stage1B FV, and FSP-M binary as a FILE

    • Stage 1B FV: Contains CfgDataInt.bin, and Stage1B PEIM


  • Stage 2:

    • Packaged As: FD containing Stage2 FV, and FSP-S binary as a FILE

    • Stage 2 FV: Contains ACPI Table, Vbt, Logo, and Stage2 PEIM


  • OsLoader:

    • Packaged As: FD containing OsLoader FV


  • FwUpdate:

    • Packaged As: FD containing Firmware Update FV

    • Note that FwUpdate is included only if ENABLE_FWU is enabled in BoardConfig.py

  • In addition to the Slim Bootloader Stages and the payloads, the final SBL image may include some other components like Microcode binaries, ACM binary, SBL container binaries, etc.

Post Build Image Construction

  • Each stage and component of Slim Bootloader is individually built and then put together into one image at the end of the build process.

  • The final image layout for Slim Bootloader can be defined in BoardConfig.py - GetImageLayout()

    • If firmware resiliency is enabled, the layout will typically contain redundant copies of the boot-critical code. Check Firmware Resiliency and Recovery for more details.

  • As discussed above, the final SBL image includes SBL stages and other components, examples of which are listed below:

    • These additional components included in the SBL image are placed in the non-redundant region of the image

    • The list of components in the final image in the final image is present in the GetImageLayout() function

    • Examples:

      • ACM.bin - Authenticated Code Module

      • MRCDATA.bin - Memory Reference Code Data, used to store Memory Reference Code training data

      • VARIABLE.bin - This region is used for GetVariable() and SetVariable() APIs provided by LiteVariableLib in BootloaderCommonPkg

      • UCODE.bin - CPU Microcode

      • The components listed above are generated by the post_build() function in BuildLoader.py

    • Payloads other than OsLoader and FW Update are built independently and the payload binary is packaged as EPAYLOAD.bin to be included in the final SBL image

      • EPAYLOAD.bin - Payload for SBL - used for extra payloads (UEFI Payload, Linux, u-boot, etc.). Refer to Integrate Multiple Payloads for more details.

    • SBL images can also include container images and SBL containers can be built with the container tool (Container Tool) and included in the SBL image as explained below (Adding an SBL Container)

Patching of stages

Patching of stages is done to allow for code simplicity and for faster booting. The addresses of certain elements like BFV, FIT, FlashMap, etc. are pre-loaded into the SBL binary at pre-defined locations.

  • Stage 1A:

    • The Boot Firmware Volume (BFV) address needs to be placed as the the last DWORD of memory. Thus, the BFV needs to be placed as the last DWORD of Stage 1A. And this BFV will be mapped to the memory address 0xFFFFFFFC (top of memory - 4).

      Thus, in the image layout, BFV will be patched onto (top of Stage 1A - 0x04) address.

      Note

      When passing a negative offset to patch_fv(), it is considered relative to 4GB (0xFFFFFFFF)

      Thus, the final offset will be equal to : FileSize - (0xFFFFFFFF - offset + 1)

      This can be seen in patching of BFV, FlashMap, and FIT.

    • Stage 1A Entry point is patched onto the Stage 1A __ModuleEntryPoint symbol address

    • Stage 1A Module base is patched onto entry point + 4

    • Address of VerInfo file (GUID: 3473A022-C3C2-4964-B309-22B3DFB0B6CA) is patched onto PcdVerInfoBase PCD

    • Address of PcdFileDataBase (GUID: EFAC3859-B680-4232-A159-F886F2AE0B83) is patched onto PcdFileDataBase PCD

    • Address of FlashMap (GUID: 3CEA8EF3-95FC-476F-ABA5-7EC5DFA1D77B) is patched onto 0xFFFFFFF8 (top of Stage 1A - 0x08)

    • Address of Firmware Interface Table (FIT) is patched onto memory address 0xFFFFFFC0 (top of Stage 1A - 0x40)

      • FIT Signature Low, FIT Signature High, and FIT table max length are patched onto offsets 0, 4, and 8 respectively.

      • FIT entries are generated by BuildLoader.py - update_fit_table() at build time.

    • Address of HashStore is patched onto PcdHashStoreBase PCD


  • Stage 1B:

    • Stage 1B entry point address is patched into the Stage 1B __ModuleEntryPoint symbol address

    • Stage 1B module based is patched onto entry point + 4

    • Address of Internal CfgDataBase (GUID: 016E6CD0-4834-4C7E-BCFE-41DFB88A6A6D) is patched onto PcdCfgDataIntBase PCD


  • Stage 2:

    • Stage 2 entry point address is patched into the Stage 2 __ModuleEntryPoint symbol address

    • Stage 2 module based is patched onto entry point + 4

    • Address of VBT (GUID: E08CA6D5-8D02-43AE-ABB1-952CC787C933) is patched onto PcdGraphicsVbtAddress PCD

    • Address of ACPI Table (GUID: 7E374E25-8E01-4FEE-87F2-390C23C606CD) address is patched onto PcdAcpiTablesAddress PCD

    • Address of Splash Logo (GUID: 5E2D3BE9-AD72-4D1D-AAD5-6B08AF921590) address is patched onto PcdSplashLogoAddress PCD

Post Build Customization

SBL supports platform customizations by embedding configuration data in a dedicated region in the image. The configuration data region can be patched without recompiling the code. This feature is most useful in supporting multiple similar boards in a single SBL image.

Adding an SBL Container

  • It may be required to include additional binary components to the final SBL image.

  • The required components can be added to the image as SBL containers

  • GetContainerList() initially creates a blank list, and then adds each container entry into this list

  • The list of containers included in the final SBL image can be seen in the platform’s BoardConfig.py - GetContainerList() function

  • GetContainerList() returns a list of containers. Each container entry is also a list consisting of several different fields shown in the example below

  • Make sure that the existing entries in the function are being put into container_list as one list

  • To create a new container, you will need to create a list where the first entry lists the container, and the remaining list the components inside it

    • Example:

      Adding files named test1, test2, test3 to a container named “SBLC” will be done as follows:

      def GetContainerList (self):
        container_list = []
        ...
        ...
        container_list.append([
          # Name      |      File             |    CompressAlg  |               AuthType             | Key File                                       | Region Align   | Region Size |  Svn Info
          ('SBLC',      'SBLC.bin',                 '',             container_list_auth_type,        'KEY_ID_CONTAINER'+'_'+self._RSA_SIGN_TYPE,            0,                0     ,      0),
          ('TST1',      '/path/to/test1',           '',             container_list_auth_type,        'KEY_ID_CONTAINER_COMP'+'_'+self._RSA_SIGN_TYPE,       0,                0     ,      0),
          ('TST2',      '/path/to/test2',           '',             container_list_auth_type,        'KEY_ID_CONTAINER_COMP'+'_'+self._RSA_SIGN_TYPE,       0,                0     ,      0),
          ('TST3',      '/path/to/test3',           '',             container_list_auth_type,        'KEY_ID_CONTAINER_COMP'+'_'+self._RSA_SIGN_TYPE,       0,                0     ,      0)3
        ])
        ...
        ...
      

      This will create a container named SBLC.bin

  • This .bin file needs to be added to the SBL image layout so that it can be included in the final image

    • In the platform’s BoardConfig.py, we need to add the size of the required component.

    • In GetImageLayout(), add the component to the non-redundant section

    • Example:

      class Board:
        ...
        ...
        self.SBLC_SIZE = 0x1000
      
        ...
        def GetImageLayout():
          ...
          ...
          img_list.extend ([
            ('NON_REDUNDANT.bin', [
                  #  File     |   Compression   |       Size      |    Stitch Mode     |     Stitch Position
                  ('SBLC.bin'   ,     ''        , self.SBLC_SIZE,   STITCH_OPS.MODE_FILE_PAD, STITCH_OPS.MODE_POS_TAIL),
                  ...
                  ...
                  ]
              )
          ])
          ...
          ...
      

Release vs Debug Build

SBL build system provides building debug or release images. Debug build contains verbose log messages for debugging, while release build image is deployed in a production environment. It contains minimum log messages to the console, and in some cases, may be built with more secure configurations, compared to debug build image.

Build system builds debug SBL image by default. To build a release image:

python BuildLoader.py build <target> -r

Note

When verified boot is enabled, SBL release build requires container image format to boot OS.

Developing on Windows

Note

Typically, Windows C compiler generates smaller code size compared to GCC build. This needs to be considered when allocating image size in SBL build.