Skip to content

Configuration Modules Platform Integration

Table of Contents

Description

The configuration modules source code is intended to be used with some library classes provided by platforms. In order to integrate configuration modules into a platform's firmware it is important to consider higher-level integration challenges specific to the platform in addition to the required code changes to integrate all of the pieces.

High-Level Considerations

  1. Configuration Apps Changes - The setup variable feature will replace an existing UI application and switch to serial base console input/output. All agents will leverage Policy Service to set/get configurations.

  2. Silicon Code Changes - The silicon firmware may need changes for:

    1. Add depex statement for drivers to load after Policy Service, the Config Policy to Silicon Policy Mapper(s), and the relevant default silicon policy producer(s)
    2. Locate policy protocol/ppis for silicon configuration
    3. Adding default silicon policy producers
  3. Platform Data Flow - Modules provided in this package for platform to load/update configuration data.

  4. Platform Data Consumption - Description of expected platform workflow on how to consume data from configuration knobs to convert to policy data.

    1. Add PlatformConfigDataLib with autogenerated data header
    2. Add OemConfigPolicyCreator to receive data from PlatformConfigDataLib and publish the config policy.
    3. Add 1 - n Config Policy to Silicon Policy Mapper(s) to take config policy and override the default silicon policies.
  5. Configuration App Code Integration - How to best integrate the SetupDataPkg collateral into a platform firmware.

  6. Profiles Integration - How to integrate Configuration Profiles into platform firmware.

Configuration Apps Changes

Instead of rendering all available options in the UEFI front page, which is backed by HII data and complicated UI frameworks, the configuration applications will focus on configuration data pipeline and actual functionality.

More of this data flow will be documented in Platform Data Flow section.

Silicon Code Changes

For each applicable silicon driver that needs to be configured during UEFI operation, the silicon driver needs to be updated to pull silicon policy data for its configuration.

For each configurable silicon feature/component/module, one needs to define a structure that contains all necessary settings. These settings will be populated with a default value during the PEI phase by a default silicon policy producer.

When a silicon module is executed, the consuming module should fetch its silicon policy data from Policy Service and configure the hardware accordingly.

Platform Data Flow

The default silicon policy can be initialized by silicon modules during early PEI after Policy Service is available, and then updated by a phase-2 module to apply the changes from configuration data to silicon policy.

The OemConfigPolicyCreator should take the autogenerated data provided by PlatformConfigDataLib (via the gKnobData extern structure) and publish the config policy. This module can perform any filtering required by the OEM/platform, such as overriding the config knobs with updated values from variable storage or a different configuration profile. An example is provided in mu_oem_sample. An example PlatformConfigDataLib is provided in mu_tiano_platforms.

Following these two operations, the n number of Config Policy to Silicon Policy Mappers will run, consume the config policy and override the relevant silicon policies. An example is provided in mu_tiano_platforms.

Note that, for demonstration simplicity and data overhead reduction, the provided example above directly intialized the silicon policy and update the value using data from configuration autogen headers. In real world, this same model could also be considered as long as this model would not cause dependency intervention. More often though, existing silicon modules from major silicon vendors might already have their data pipelines, such as setup variables, structured PCDs. In those cases, platforms can consider updating the data that resides in the existing pipelines instead of introducing major silicon module overhaul.

During the rest of boot process, the silicon drivers will consume the updated silicon policies to configure hardware components or adjust firmware configuration. An example is provided in mu_tiano_platforms.

Platform Data Consumption

In order for drivers provided by this package to function as expected, the platform owners are suggested to author the following routines to properly consume configuration data:

Platform Silicon Policy Initialization

Per silicon policy definition, platforms are responsible for initializing each silicon policy with default values for the case that its corresponding configuration policy is not present.

Platform Config Knob Shim Library

ConfigKnobShimLib provides an interface to query overrides to config knobs. This queries variable storage for any appropriately sized overrides to config knobs.

PlatformBuild.py Changes

The platform must define CONF_AUTOGEN_INCLUDE_PATH in PlatformBuild.py. This is the absolute path that the autogenerated header files will be placed under as such: CONF_AUTOGEN_INCLUDE_PATH\Generated\Config*.h. The UpdateConfigHdr.py build plugin will create the Generated directory if it does not exist. If there are multiple environments being built in one build, e.g. StandaloneMM and DXE environments with separate config, PlatformBuild.py may put a semicolon delimited list of include paths here such as:

self.env.SetValue("CONF_AUTOGEN_INCLUDE_PATH", "MyPkg/Include;MyPkg/Include/StandaloneMm", "Platform Defined")

This list must be the same length as the MU_SCHEMA_FILE_NAME and it will be processed in the same order; the first schema file will get headers generated to the first include directory, etc.

The platform must define MU_SCHEMA_DIR and MU_SCHEMA_FILE_NAME in PlatformBuild.py. These are the directory containing the XML configuration file and the file name of the XML configuration file, respectively. These are split apart to allow the CI build to discover a test schema to validate this process.

MU_SCHEMA_FILE_NAME may have multiple schema files that are semicolon delimited if the build has multiple environments being built at the same time, e.g. StandaloneMM and DXE. If so, CONF_AUTOGEN_INCLUDE_PATH must have the same number of entries, see above. An example is:

self.env.SetValue("MU_SCHEMA_FILE_NAME", "NonSecureConfig.xml;StMMConfig.xml", "Platform Defined")

Autogenerated Header Files

There are four autogenerated headers and one standard structure definition header:

  • <Generated/ConfigClientGenerated.h> - The Client header
  • <Generated/ConfigServiceGenerated.h> - The Service header
  • <Generated/ConfigDataGenerated.h> - The Data header
  • <Generated/ConfigProfilesGenerated.h> - The Profile header, not used if there are no profiles
  • <ConfigStdStructDefs.h> - The Standard Structure Definition header

The PlatformConfigDataLib includes, in this order, the standard structure definition header, the client header, the data header, and the profile header (if profiles are used). In this way the structure and enum definitions are populated before the data and profile headers attempt to use them. Note that these definitions may be #included in instead of declared in-file dependent upon the schema's usage of the optional headerRef attribute, and care must be taken for the consuming build system to be aware of the implicit pathing requirement to all attributed headerRefs.

The OEM platform config policy creator only include the standard structure definition header so that it can operate on the KNOB_DATA and PROFILE structures with generic data.

The Config Policy to Silicon Policy Mapper(s) include, in this order, the standard structure definition header, the client header, and the service header. In this way the structure and enum definitions as well as the getter definitions are available for the code using the getters. In our mu_tiano_platforms example, the Config Policy to Silicon Policy Mapper is compiled with several C files that only include the client header, as the service header is only needed once per module to query the config knobs out of the config policy.

The getter functions are implemented in the service header file. The traditional way to fetch a knob value will be to call the getter function with the knob name by supplying the pointer to hold such knob (i.e. ConfigGetKnob1 (&Knob)).

Alternatively, getter functions can also be called with a knob name and a size-specified buffer. In this case, the getter function will inspect the cache buffer and try to populate the content if it is uninitialized. The caller should keep note of the intialized buffer for subsquent calls in the same module for optimal performance. The caller should also be aware that the buffer size should be large enough (CACHED_POLICY_SIZE + CACHED_POLICY_HEADER_SIZE) to hold the knob value. The usage of this alternative could work around the limitation of the traditional way that the relies on global variables when the modules are XIP (execute in place).

The Silicon Policy Consumers do not need to include any of the above headers and will instead fetch their configuration directly from silicon policy.

KnobService

The four generated headers described in the Autogenerated Header Files section above are produced by KnobService. For more information on tool usage, please refer to the following tool help text below:

generateheader[_efi] [] [ ...]

  • schema.xml: An XML with the definition of a set of known config knobs and types to interpret them.
  • public_header.h: Output header for use by config consumers.
  • service_header.h: Output header for use by config provider. In UEFI builds this only contains getter implementations.
  • data_header.h: Output header for UEFI builds only. This contains only the data. In non-UEFI builds, service_header.h and data_header.h are combined.
  • profile_header.h: Output header for the profile data for consumption by config providers.
  • profile.csv...: n-number of profile csvs that describe the platform's overridden config knobs.
  • pn names: n-number of 2-character profile names that uniquely identify the profiles specified in profile.csv.
  • pid ids: n-number of 1-byte hexadecimal (prepend with 0x) profile id that uniquely identify the profiles specified in profile.csv.
  • -t: Option flag to enable 'types only' outputting, forcing the generation of public_header.h with Enum/Struct type declarations only. service_header.h generation is skipped if this option is used.
  • -nc: Option flag to enable 'no change' behavior which disables any type name modifications from the input schema. All names become passthrough.

Config Knob Validation Functions

The Project Mu XML based configuration provides an OEM/platform with the ability to provide config knob validation functions to run against config knob overrides to ensure they meet the requirements for a knob. These functions can be added to the KNOB_DATA structure's Validator field, say in PlatformConfigDataLib and then run in the OEM Config Policy Creator after it fetches overrides. If any overrides fail validation (say a value too large), the default config knob value can be used instead.

Configuration App Code Integration

  1. Ensure all submodules for the platform are based on the latest Project Mu version (check the HEAD of each repo)
  2. The prerequisites of this feature is Policy service and Project MU based BDS. This guideline will omit the integration steps for these features.

Platform DSC statements

Add the DSC sections below in addition to the OemConfigPolicyCreator, PlatformConfigDataLib, Default Silicon Policy Creators, and Config Policy to Silicon Policy Mapper(s).

[PcdsFixedAtBuild]
  # The GUID of SetupDataPkg/ConfApp/ConfApp.inf: E3624086-4FCD-446E-9D07-B6B913792071
  gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x86, 0x40, 0x62, 0xe3, 0xcd, 0x4f, 0x6e, 0x44, 0x9d, 0x7, 0xb6, 0xb9, 0x13, 0x79, 0x20, 0x71 }

[LibraryClasses]
  SvdXmlSettingSchemaSupportLib |SetupDataPkg/Library/SvdXmlSettingSchemaSupportLib/SvdXmlSettingSchemaSupportLib.inf
  ConfigVariableListLib         |SetupDataPkg/Library/ConfigVariableListLib/ConfigVariableListLib.inf

[LibraryClasses.common.PEIM]
  ConfigKnobShimLib|SetupDataPkg/Library/ConfigKnobShimLib/ConfigKnobShimPeiLib/ConfigKnobShimPeiLib.inf

[Components.X64, Components.AARCH64]
  #
  # Setup variables
  #
  SetupDataPkg/ConfApp/ConfApp.inf {
    <LibraryClasses>
      JsonLiteParserLib|MsCorePkg/Library/JsonLiteParser/JsonLiteParser.inf
  }

[PcdsFixedAtBuild]
  # this GUID should be whatever the OEM Config Policy Creator uses as the Config Policy GUID
  # this is the example GUID from mu_oem_sample. It is used so ConfApp can dump the configuration policy.
  gSetupDataPkgTokenSpaceGuid.PcdConfigurationPolicyGuid|{GUID("ba320ade-e132-4c99-a3df-74d673ea6f76")}

Remove the DSC sections below.

[Components.X64, Components.AARCH64]
  # MdeModulePkg/Application/UiApp/UiApp.inf {
  #   <LibraryClasses>
  #     NULL|MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
  #     NULL|MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
  #     NULL|MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
  #     PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
  # }

Platform FDF statements

Add the FDF sections below.

Note: This is change is on top of Project MU based BDS and DFCI feature.

[FV.YOUR_DXE_FV]
  INF SetupDataPkg/ConfApp/ConfApp.inf

Remove the FDF sections below.

[FV.YOUR_DXE_FV]
  # INF MdeModulePkg/Application/UiApp/UiApp.inf

Standalone MM Configuration

This repository also supports configuration in standalone MM. The expectation is that a separate configuration XML is used for standalone MM vs PEI/DXE, which produces separate autogenerated headers. All information in this document is valid, but substitute the standalone MM modules (e.g. ConfigKnobShimLibStandaloneMm) in place of the PEI/DXE ones.

Profiles Integration

In order to use configuration profiles, the platform must include the above changes as well as csv change files for each profile that are overrides on top of the generic profile. These are created through the Config Editor UI tool by choosing Save Config Changes to Change File or Save Full Config to Change File (more details in the Configuration Files doc).

The platform must then set CONF_PROFILE_PATHS as a space separated string of paths to CSVs in PlatformBuild.py, e.g.:

self.env.SetValue('CONF_PROFILE_PATHS',
                            self.mws.join(self.ws, 'Platforms', 'PlatformPkg', 'Config', 'Profile1.csv'),
                            self.mws.join(self.ws, 'Platforms', 'PlatformPkg', 'Config', 'Profile2.csv')
)

The platform must then implement the ActiveProfileIndexSelectorLib library class to correctly pick the profile index for this platform on a given boot.

Finally, the OEM/platform would update its config policy creator to query the index from ActiveProfileIndexSelectorLib and apply the overrides from gProfileData.

For full profile details, see the Profile Doc.