↓ Skip to main content

AMI Aptio 4 OEM eModule: Architecture, Linking, and Overrides

AMI Aptio 4 OEM eModule: Architecture, Linking, and Overrides

AMI Aptio 4 provides a UEFI firmware development framework that enables motherboard manufacturers to initialize hardware, configure platform features, and implement board-specific functionality. For OEMs, maintaining these customizations independently from the firmware core is essential for managing product variants, integrating new hardware, and adopting future core updates.

The OEM eModule (OEMEM) is an AMI customization mechanism whose design originated in AMI Core 8. It separates OEM-specific implementation code from the AMI core source tree and integrates custom functionality through compile-time source overrides, object-file linking, and eLink configuration.

Instead of directly modifying core source files throughout the project, developers can organize custom code in dedicated OEMEM modules and control where that code is compiled, linked, and invoked.

The architecture centers on three phase-specific modules: OEMPEI, OEMDXE, and OEMSMI. Supporting mechanisms include OEM ModuleParts, SDL and MAK build definitions, eLink relationships, and source-file overrides for C, header, assembly, VFR, UNI, and Setup-related SD files.

This guide explains the OEMEM architecture, module creation workflow, parent-module linking, Makefile configuration, file-override processing, and build-log verification.

For a broader introduction to UEFI firmware architecture and its boot flow, see UEFI BIOS Explained: Architecture and Boot Flow.

🧩 1. Understanding the OEM eModule Architecture
#

The OEMEM design separates board-level customization from core firmware implementation while retaining integration with the existing Aptio 4 build system.

1.1 Core design principles
#

OEMEM follows three primary principles:

Separation of customization and core code: OEM-specific functions are maintained in dedicated modules rather than requiring direct edits to AMI core source files.

Build-time integration: Custom functions are compiled into object files and linked into the appropriate OEM carrier modules. Source overrides allow selected core files to be replaced during the build process.

Configurable integration: eLink definitions specify relationships between OEM functions and their parent modules, including linking priorities and invocation order where supported.

These mechanisms allow an OEM to maintain its own implementation while preserving a clearer boundary between vendor-provided code and board-specific changes.

However, the separation does not eliminate all upgrade work. Changes in core interfaces, build rules, tokens, and module dependencies must still be reviewed when moving to another Aptio 4 core release.

1.2 Creating a board-specific OEMEM configuration
#

The OEMEM creation process begins by establishing the board flavor module and identifying the required platform customizations.

Typical activities include:

  • Adding board-level Option ROM components.
  • Integrating device-specific EFI drivers.
  • Cloning project tokens required for board-level features.
  • Creating OEMEM constituent modules.
  • Configuring module relationships and source overrides.

The resulting OEMEM structure may include the following components:

Component Purpose
Core Modification Module (coremod) Overrides selected core source files during the build process
OEM PEI modules Integrate OEM customization into the PEI phase
OEM DXE modules Integrate OEM customization into the DXE phase
OEM SMI modules Integrate OEM functionality associated with system management interrupts
OEM Event modules Support OEM-specific event processing
OEM eLink modules Define relationships and integration points between modules
Additional OEM modules Implement other board-specific functionality

Not every project requires every module type. The actual structure depends on platform requirements, existing core functionality, and the customization points exposed by the project.

🏗️ 2. OEMPEI, OEMDXE, and OEMSMI Driver Structure
#

The three principal OEMEM carrier modules are OEMPEI, OEMDXE, and OEMSMI. Together, they provide phase-specific integration points for OEM functions.

The architecture also supports centralized source modification through the OEMEM core modification module.

2.1 The three carrier modules
#

OEMPEI integrates OEM functions associated with the Pre-EFI Initialization (PEI) phase. These functions are appropriate for platform initialization tasks that must run before the DXE environment becomes available.

OEMDXE integrates OEM functions associated with the Driver Execution Environment (DXE). It provides an integration point for functionality that depends on the services and drivers available during the DXE phase.

OEMSMI integrates OEM functions associated with system management interrupt processing. Its implementation must conform to the platform’s existing SMI handling and initialization requirements.

These modules act as integration containers for OEM functions. Their roles are determined by the firmware phase in which the functionality must execute, rather than simply by the source file’s location.

2.2 How OEM functions are compiled and linked
#

The OEMEM build process separates source compilation from carrier-module integration.

A simplified build flow is:

OEM-specific source files
          |
          v
   Compile into .obj
          |
          v
   OEMPEI / OEMDXE / OEMSMI
          |
          v
   eLink integration
          |
          v
   Firmware image

The exact dependencies and linking rules are project-specific, but the central principle remains the same: OEM functions are compiled independently and linked into the appropriate carrier module.

The OEMEM core modification mechanism complements this process by replacing selected source files before compilation, allowing an OEM to change core behavior without editing the corresponding files in the original core directory directly.

2.3 OEMEM versus traditional OEM driver development
#

Dimension Aptio OEM eModule Traditional direct OEM driver development
Code organization Centralized OEMEM directory structure Customizations may be distributed across the project
Core source relationship Uses compile-time overrides and module integration May require direct modifications to core files
Module integration eLink manages relationships and supported ordering Integration is often configured through existing project build definitions
Customization reuse Dedicated modules can be reused across compatible board configurations Reuse depends on how custom drivers and modifications are organized
Core upgrades Clearer separation helps identify OEM-specific changes Directly modified core files may require manual merging
Traceability Build logs can help identify selected overrides and compilation paths Traceability depends on the project’s build and change-management practices

OEMEM improves the organization and traceability of customization code, but it does not guarantee automatic compatibility with every future core version. OEMs still need to verify interfaces, dependencies, and initialization order.

🔧 3. Creating an OEM ModulePart
#

An OEM ModulePart provides a structured way to add a custom function to OEMEM and connect it to the appropriate carrier module.

The VEB development tool is used to create the ModulePart and generate the associated project files.

3.1 Generate the ModulePart files
#

Use VEB to create an Oem ModulePart. The tool generates the relevant source and build-definition files, typically including:

  • An SDL file containing module configuration and token definitions.
  • A MAK file containing compilation and build rules.
  • A C source file implementing the OEM functionality.
  • A header file declaring the function interfaces and required definitions.

The exact generated files and directory layout depend on the project template and VEB configuration.

Keep the generated module within the intended OEMEM directory structure so that the build system can locate its source files and process its definitions.

3.2 Define eLink relationships in the SDL file #

The ModulePart SDL file must define its integration with the parent carrier modules.

The OEM function should be linked to the appropriate core list associated with OEMPEI, OEMDXE, or OEMSMI, according to the phase in which it needs to execute.

For functions that need to participate in more than one phase, define the required relationships separately and ensure that each implementation is appropriate for its target environment.

When configuring these relationships, verify:

  • The parent module is correct.
  • The OEM function is included in the intended core list.
  • The linking priority is appropriate.
  • The invocation order satisfies initialization dependencies.
  • The relevant definitions are enabled for the intended board configuration.

The exact eLink syntax should follow the conventions used by the target Aptio 4 project rather than a generic template.

3.3 Configure object paths and include directories
#

The ModulePart MAK file defines the compilation and integration details for the OEM function.

Typical responsibilities include specifying:

  • The source files to compile.
  • The output .obj file path.
  • Required header include directories.
  • The applicable compiler options.
  • The build directory and output target.

Ensure that the object file is generated in the directory expected by the parent build rules. An incorrectly configured output path can result in missing-object errors or stale objects being reused.

3.4 Verify the eKernel configuration
#

After configuring the ModulePart, inspect the eKernel table to confirm that the relevant eLink definitions have been generated.

Check that the OEM function appears under the intended parent module and that its linking and invocation properties match the SDL configuration.

This verification helps detect configuration errors before investigating lower-level compiler or linker failures.

🔗 4. Linking ModuleParts to Parent Modules
#

The eLink mechanism establishes the relationship between an OEM ModulePart and its parent module or module list.

The configuration for OEMPEI, OEMDXE, and OEMSMI follows the same general principle, although the parent lists and target object definitions differ.

4.1 Configure the parent and execution order
#

When linking an OEM function, verify the following properties:

Configuration item Validation requirement
Parent References the intended OEMPEI, OEMDXE, or OEMSMI integration point
ModulePart Identifies the OEM function being integrated
Priority Follows the target project’s ordering conventions
InvokeOrder Places the function appropriately relative to its dependencies
Build configuration Enables the module for the intended platform and build variant

Priority and invocation order should not be treated as interchangeable concepts unless the target project’s eLink implementation defines them that way.

A function that depends on another module’s initialization must not execute before the required dependency is available.

For PEI, DXE, and SMI customizations, validate ordering against the initialization requirements of the relevant firmware phase.

4.2 Confirm generated integration data
#

After building or generating the project configuration, inspect the eKernel table to verify that the eLink has been created and resolved correctly.

If a module is missing, check its SDL declarations, parent-list references, conditional tokens, and module configuration before changing compiler rules.

Keeping eLink configuration separate from source implementation makes integration easier to diagnose and maintain.

🛠️ 5. Configuring PEI, DXE, and SMI Makefiles
#

The OEMEM Makefile configuration defines how OEM functions are compiled into object files and made available to the carrier modules.

The PEI, DXE, and SMI MAK files follow the same general structure. They differ primarily in object names, target directories, and phase-specific build definitions.

5.1 Define the object-file target
#

Taking PEI as an example, the MAK file needs to define the target associated with the OEMPEI object file.

The build rules typically specify:

  • The target .obj file.
  • The source dependencies.
  • The C compiler invocation.
  • The OEMEM_CFLAGS compilation switch.
  • The required include directories.
  • The logic for creating the output directory.

When adapting the configuration for DXE or SMI, replace the PEI-specific object names and output paths with the corresponding phase-specific definitions.

Do not assume that changing only the object filename is sufficient. Verify that the compiler flags, dependencies, and target directories match the intended carrier module.

5.2 Apply OEMEM compilation options
#

The OEMEM_CFLAGS switch provides the OEMEM-specific compiler options required by the project.

The actual flags should be consistent with the surrounding Aptio 4 build environment, including the target architecture, compiler version, include paths, and definitions used by the parent module.

Avoid independently changing options that affect structure layout, calling conventions, or other binary interfaces unless the target project explicitly requires them.

5.3 Create build directories automatically
#

The MAK rules should create the target directory when it does not exist.

This avoids failures when performing a clean build or switching between board configurations in which the output directories have not yet been generated.

The PEI, DXE, and SMI variants should use their intended target directories to prevent unrelated object files from being mixed across phases.

After updating the MAK files, perform a clean build and confirm that each object is generated in the expected location.

📂 6. Understanding the OEMEM File-Override Mechanism
#

Source-file overriding allows OEMEM to substitute selected project files with OEM-maintained versions during the build process.

This mechanism is particularly useful when an OEM needs to change existing core behavior but wants to keep the replacement implementation separate from the original source tree.

6.1 Configure the core modification rules
#

The documented process begins by replacing the original project file:

project\core\Rules.mak

with the OEMEM version located at:

SRC-Mod\Rules.mak

The OEMEM configuration then identifies the directory containing override files through CORE_OVERRIDE.SDL.

The core-version tokens used by the project include:

  • CORE_MAJOR_VERSION
  • CORE_MINOR_VERSION
  • CORE_REVISION
  • CORE_BUILD_NUMBER

These tokens help identify the core version against which the override configuration is intended to operate.

The override directory and replacement rules must be consistent with the target project. An override prepared for one core release may not be suitable for another if the original source structure or function interfaces have changed.

6.2 How source files are replaced during compilation
#

During the build process, OEMEM uses CIF2MAK.exe and the configured Makefile rules to select and apply the relevant overrides.

For C and header files, the documented mechanism replaces corresponding files in the project with versions supplied through the OEMEM codeMod directory.

The OEMEM Rules.mak also handles overrides for UNI and VFR files, replacing the corresponding project inputs during compilation.

The overall process can be represented as:

OEMEM codeMod override files
              |
              v
   CORE_OVERRIDE.SDL
              |
              v
   Rules.mak / CIF2MAK.exe
              |
              v
   Select and apply overrides
              |
              v
   Compile the modified project

The exact behavior depends on the configured source type and build rules. Assembly sources and other supported file classes should be verified through their actual compilation commands rather than assumed to follow an identical replacement path.

6.3 Supported override categories
#

The documented workflow includes the following file types:

File type Example Verification target
C source meminit.c Compiler input path in build.log
Header AmiDxeLib.h Compiler include path and included-file output
Assembly SMBiosStaticData.asm Assembly input path in build.log
VFR Main.vfr Input path of the VFRCOMPILE command
UNI strings CPU.uni Input path of the STRGATHER command
Setup SD SB.sd Parent replacement and eKernel configuration

Each override type has a different point in the build pipeline, so verification should use the tool that actually consumes the file.

🔍 7. Verifying File Overrides Through Build Logs
#

The build log is the primary diagnostic source for determining whether an OEMEM override was applied successfully.

By default, brief build output may omit the paths needed to confirm file selection. Disabling the BRIEF token provides more detailed output for inspection.

7.1 Verify a C source override
#

Consider an override for meminit.c.

Search for the file in build.log and inspect the compiler command.

A successful override should show the source path associated with the intended OEMEM override or project location after the replacement has been applied, depending on how the project’s build rules represent the selected file.

Do not rely solely on the presence of the filename. Confirm the resolved path to ensure that the compiler is consuming the intended implementation.

7.2 Verify a header override
#

Header overrides require a different diagnostic approach because a source file may include a header indirectly through several levels of dependencies.

To display header inclusion paths, add the following setting to RulesMode.mak:

MY_DEFINES = /showIncludes $(MY_DEFINES)

Rebuild the relevant target and search the detailed build log for AmiDxeLib.h.

The reported inclusion path should identify which header file the compiler actually opened. This is more reliable than checking only the project’s include-directory definitions, because the same filename may exist in several directories.

Use the diagnostic option only as needed for investigation and follow the project’s established build configuration when returning to the normal build process.

7.3 Verify an assembly override
#

For an assembly file such as SMBiosStaticData.asm, inspect its entry in build.log.

Locate the assembly compilation or processing command and confirm the input path.

If the command still references the original project source when an OEMEM override is expected, check the override directory, file-selection rules, and the assembly-specific Makefile configuration.

7.4 Verify a VFR override
#

For Main.vfr, search the log for the VFRCOMPILE command.

Inspect the command’s input filename and confirm that it points to the intended override file.

This check is important because VFR files are processed by a dedicated compiler rather than the ordinary C compiler. A correct C-source override does not establish that the VFR replacement was selected as well.

7.5 General verification procedure
#

For every override, verify three things:

  1. Selection: The build system has identified the intended replacement file.
  2. Consumption: The appropriate compiler or build tool is using that file.
  3. Result: The build completes successfully, and the resulting firmware contains the expected behavior.

The third step matters because a correct input path does not, by itself, prove that the modified functionality is correctly linked or executed at runtime.

🖥️ 8. Overriding Setup SD Files and UNI Strings
#

OEMEM also provides mechanisms for customizing Setup-related definitions and displayed strings without directly modifying the corresponding project files.

8.1 Replacing a Setup SD file
#

To override an SD file, clone the original file into the intended OEMEM location and configure the eLink relationship to use ReplaceParent.

For example, an OEM may create a replacement for SB.sd and link it to the relevant parent entry.

After configuring the replacement, inspect the BIOS eKernel table to confirm that the intended SD file has replaced the original parent entry.

Validate that the replacement remains compatible with the surrounding Setup definitions and the target firmware build.

The exact file path, parent module, and eLink syntax depend on the Aptio 4 project.

8.2 Redefining UNI strings
#

OEMEM can redefine selected project UNI strings through oememfaketoken.c and oememfaketoken.uni.

This mechanism provides a way to supply OEM-specific string definitions while keeping them separate from the original project string files.

String identifiers and their associated definitions must be positioned consistently in both files. An inconsistent identifier or mapping can cause the intended string to be missing, incorrectly referenced, or replaced by an unintended value.

Review the existing project conventions before adding or changing definitions.

8.3 Verify UNI replacement through STRGATHER
#

To verify an override such as CPU.uni, inspect build.log and locate the STRGATHER invocation.

Confirm that the input path points to the intended OEMEM UNI file rather than the original project file.

This provides direct evidence that the replacement participates in string processing. The final firmware should also be checked to confirm that the intended text appears in the correct Setup location.

✅ 9. Best Practices for Maintaining OEMEM Customizations
#

OEMEM provides a cleaner customization boundary, but reliable firmware integration still requires disciplined configuration and validation.

Keep overrides minimal and version-aware
#

Override only the files required to implement the OEM feature. A smaller override set reduces the likelihood of diverging from future core changes.

Track the target core version using the project’s version tokens and review each replacement when updating the core.

A source file that compiles against one release may depend on private functions, structures, or build conventions that have changed in another.

Validate module ordering and phase dependencies
#

Check the eLink parent, priority, and invocation order for every OEM function.

Make sure the function runs in the appropriate phase and that dependencies are available before it executes.

For changes spanning PEI, DXE, and SMI, verify that each carrier’s integration and build configuration are correct rather than assuming that a successful build of one phase validates the others.

Verify the build pipeline, not only the configuration files
#

A directory entry or SDL declaration does not prove that the intended override reached the final build.

Use detailed build logs to verify compiler inputs, include paths, assembly sources, VFR processing, and UNI string gathering.

After file selection has been confirmed, perform a clean build and validate the resulting firmware on the intended platform.

Preserve a reproducible build baseline
#

For ongoing maintenance, record the core version, OEMEM override set, compiler configuration, and relevant eLink changes.

This makes it easier to distinguish an OEM customization issue from a core update, toolchain change, or build-environment problem.

It also provides a foundation for regression testing when the same OEMEM implementation must be integrated into multiple board variants.

✅ Conclusion: OEMEM Separates OEM Customization from Aptio 4 Core Development
#

AMI Aptio 4 OEM eModule provides a structured approach to board-level firmware customization through three principal carrier modules—OEMPEI, OEMDXE, and OEMSMI—combined with eLink integration, ModulePart build definitions, and compile-time file replacement.

The architecture allows OEMs to maintain custom code separately from the AMI core, control module relationships, and replace selected source files without directly editing the corresponding core files in the OEM customization workflow.

Its effectiveness depends on several mechanisms working together:

  • OEMPEI, OEMDXE, and OEMSMI provide phase-specific integration points.
  • ModuleParts and MAK files define how OEM functions are compiled into object files.
  • eLink establishes parent relationships and controls supported integration ordering.
  • CORE_OVERRIDE.SDL, Rules.mak, and CIF2MAK.exe provide the documented source-override workflow.
  • Build logs and eKernel tables make it possible to verify module integration and file selection.

For firmware engineers, the main benefit is a clearer boundary between core firmware and board-specific functionality. This organization improves maintainability and makes customizations easier to identify during core upgrades.

The key is to treat OEMEM as a build-time integration framework rather than an automatic compatibility layer. Correct source selection, consistent linking, version-aware overrides, and validation of the resulting firmware remain essential to a reliable Aptio 4 implementation.

Related