Section 23.8: ARM UEFI Porting Guide

This section provides a comprehensive guide for porting UEFI to a new ARM platform, from initial bringup through production validation.

Porting Overview

graph TB
    subgraph "Phase 1: Prerequisites"
        P1[Hardware Documentation]
        P2[TF-A Port]
        P3[Serial Console]
    end

    subgraph "Phase 2: Minimal Boot"
        M1[Platform Package]
        M2[Memory Init]
        M3[SEC Entry]
        M4[Serial Debug]
    end

    subgraph "Phase 3: Core Functionality"
        C1[PEI/DXE Transition]
        C2[GIC/Timer]
        C3[PCIe/Devices]
        C4[ACPI Tables]
    end

    subgraph "Phase 4: Validation"
        V1[Boot to Shell]
        V2[OS Boot]
        V3[ACS Testing]
        V4[Production]
    end

    P1 --> P2 --> P3
    P3 --> M1 --> M2 --> M3 --> M4
    M4 --> C1 --> C2 --> C3 --> C4
    C4 --> V1 --> V2 --> V3 --> V4

Phase 1: Prerequisites

Hardware Documentation Checklist

## Required Documentation

### SoC/CPU Information
- [ ] ARM core type (Cortex-A76, Neoverse-N1, etc.)
- [ ] Number of cores and clusters
- [ ] Cache hierarchy (L1, L2, L3)
- [ ] Exception level capabilities (EL2, EL3 support)
- [ ] PSCI implementation details

### Memory Map
- [ ] Boot ROM location and size
- [ ] SRAM location and size
- [ ] DRAM base address and max size
- [ ] DDR controller type and configuration
- [ ] Memory-mapped peripheral addresses

### Interrupt Controller
- [ ] GIC version (v2, v3, v4)
- [ ] Distributor base address
- [ ] Redistributor base addresses (GICv3+)
- [ ] CPU interface base (GICv2)
- [ ] ITS base address (if present)
- [ ] Interrupt assignments (SPI numbers)

### Timer
- [ ] Generic timer availability
- [ ] Timer frequency
- [ ] Timer interrupt numbers (secure, non-secure, virtual, hyp)
- [ ] Watchdog timer details

### Serial Console
- [ ] UART type (PL011, 8250, vendor-specific)
- [ ] UART base address
- [ ] UART interrupt
- [ ] Input clock frequency

### Boot Media
- [ ] Flash type (SPI NOR, eMMC, etc.)
- [ ] Flash base address and size
- [ ] Boot device configuration

### PCIe (if present)
- [ ] Root complex base
- [ ] ECAM base and size
- [ ] Memory windows (32-bit, 64-bit)
- [ ] I/O window
- [ ] Interrupt routing

TF-A Port

Before UEFI, ensure TF-A works on your platform:

# Minimal TF-A platform structure
arm-trusted-firmware/
└── plat/
    └── vendor/
        └── platform/
            ├── include/
            │   ├── platform_def.h     # Platform definitions
            │   └── plat_macros.S      # Debug macros
            ├── aarch64/
            │   └── platform_helpers.S # Assembly helpers
            ├── platform.mk            # Build configuration
            ├── bl1_plat_setup.c       # BL1 platform setup
            ├── bl2_plat_setup.c       # BL2 platform setup
            ├── bl31_plat_setup.c      # BL31 platform setup
            ├── plat_io_storage.c      # I/O layer
            ├── plat_psci.c            # PSCI implementation
            ├── plat_gic.c             # GIC setup
            └── plat_topology.c        # CPU topology

Phase 2: Platform Package Structure

Create EDK2 Platform Package

# Platform directory structure
edk2-platforms/
└── Platform/
    └── Vendor/
        └── PlatformPkg/
            ├── PlatformPkg.dec         # Package declaration
            ├── PlatformPkg.dsc         # Platform description
            ├── PlatformPkg.fdf         # Flash description
            ├── Include/
            │   └── Platform.h          # Platform definitions
            ├── Library/
            │   ├── PlatformLib/        # Platform initialization
            │   ├── PlatformPeiLib/     # PEI phase support
            │   └── PlatformSecLib/     # SEC phase support
            ├── Drivers/
            │   ├── PlatformDxe/        # Platform DXE driver
            │   └── UartDxe/            # UART driver (if custom)
            └── AcpiTables/
                ├── Madt.aslc           # MADT table
                ├── Gtdt.aslc           # GTDT table
                ├── Iort.aslc           # IORT table
                ├── Pptt.aslc           # PPTT table
                └── Dsdt.asl            # DSDT

Package Declaration (DEC)

# PlatformPkg.dec

[Defines]
  DEC_SPECIFICATION = 0x0001001A
  PACKAGE_NAME      = PlatformPkg
  PACKAGE_GUID      = 12345678-1234-1234-1234-123456789ABC
  PACKAGE_VERSION   = 1.0

[Includes]
  Include

[Guids]
  gPlatformTokenSpaceGuid = { 0x12345678, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 }}

[PcdsFixedAtBuild]
  # Memory configuration
  gPlatformTokenSpaceGuid.PcdDramBase|0x80000000|UINT64|0x00000001
  gPlatformTokenSpaceGuid.PcdDramSize|0x80000000|UINT64|0x00000002

  # Peripheral bases
  gPlatformTokenSpaceGuid.PcdGicDistBase|0x08000000|UINT64|0x00000010
  gPlatformTokenSpaceGuid.PcdGicRedistBase|0x080A0000|UINT64|0x00000011
  gPlatformTokenSpaceGuid.PcdUartBase|0x09000000|UINT64|0x00000020
  gPlatformTokenSpaceGuid.PcdUartClkFreq|24000000|UINT32|0x00000021

  # PCIe configuration
  gPlatformTokenSpaceGuid.PcdPcieEcamBase|0x4010000000|UINT64|0x00000030
  gPlatformTokenSpaceGuid.PcdPcieEcamSize|0x10000000|UINT64|0x00000031

Platform Description (DSC)

# PlatformPkg.dsc

[Defines]
  PLATFORM_NAME                  = Platform
  PLATFORM_GUID                  = 12345678-1234-1234-1234-123456789ABC
  PLATFORM_VERSION               = 1.0
  DSC_SPECIFICATION              = 0x0001001C
  OUTPUT_DIRECTORY               = Build/Platform
  SUPPORTED_ARCHITECTURES        = AARCH64
  BUILD_TARGETS                  = DEBUG|RELEASE
  SKUID_IDENTIFIER               = DEFAULT
  FLASH_DEFINITION               = Platform/Vendor/PlatformPkg/PlatformPkg.fdf

  # ARM core definitions
  DEFINE EDK2_ARMPLATFORMLIB     = Platform/Vendor/PlatformPkg/Library/PlatformLib

!include ArmVirtPkg/ArmVirt.dsc.inc
!include MdePkg/MdeLibs.dsc.inc

[LibraryClasses.common]
  # Platform libraries
  ArmPlatformLib|$(EDK2_ARMPLATFORMLIB)/PlatformLib.inf
  PlatformPeiLib|Platform/Vendor/PlatformPkg/Library/PlatformPeiLib/PlatformPeiLib.inf

  # Core ARM libraries
  ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
  ArmMmuLib|ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
  ArmGicLib|ArmPkg/Drivers/ArmGic/ArmGicLib.inf
  ArmGenericTimerCounterLib|ArmPkg/Library/ArmGenericTimerPhyCounterLib/ArmGenericTimerPhyCounterLib.inf

  # Serial
  SerialPortLib|ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortLib.inf
  PL011UartLib|ArmPlatformPkg/Library/PL011UartLib/PL011UartLib.inf
  PL011UartClockLib|ArmPlatformPkg/Library/PL011UartClockLib/PL011UartClockLib.inf

[LibraryClasses.common.SEC]
  PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf
  ArmGicArchLib|ArmPkg/Library/ArmGicArchSecLib/ArmGicArchSecLib.inf

[LibraryClasses.common.DXE_DRIVER]
  ArmGicArchLib|ArmPkg/Library/ArmGicArchLib/ArmGicArchLib.inf

[PcdsFixedAtBuild.common]
  # Debug output
  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F
  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8040004F

  # Memory
  gArmTokenSpaceGuid.PcdSystemMemoryBase|0x80000000
  gArmTokenSpaceGuid.PcdSystemMemorySize|0x80000000

  # UART
  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0x09000000
  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200

  # GIC
  gArmTokenSpaceGuid.PcdGicDistributorBase|0x08000000
  gArmTokenSpaceGuid.PcdGicRedistributorsBase|0x080A0000

  # Timer
  gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz|100000000
  gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum|29
  gArmTokenSpaceGuid.PcdArmArchTimerIntrNum|30
  gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|27
  gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|26

  # Firmware volume
  gArmTokenSpaceGuid.PcdFdBaseAddress|0x00000000
  gArmTokenSpaceGuid.PcdFdSize|0x00400000
  gArmTokenSpaceGuid.PcdFvBaseAddress|0x00000000
  gArmTokenSpaceGuid.PcdFvSize|0x00400000

[Components.common]
  # SEC/PrePi
  Platform/Vendor/PlatformPkg/PrePi/PrePi.inf

  # DXE Core
  MdeModulePkg/Core/Dxe/DxeMain.inf

  # Architectural Protocols
  ArmPkg/Drivers/CpuDxe/CpuDxe.inf
  ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
  ArmPkg/Drivers/TimerDxe/TimerDxe.inf

  # Platform driver
  Platform/Vendor/PlatformPkg/Drivers/PlatformDxe/PlatformDxe.inf

  # ACPI
  Platform/Vendor/PlatformPkg/AcpiTables/AcpiTables.inf

Platform Library Implementation

// Library/PlatformLib/PlatformLib.c

#include <Library/ArmPlatformLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/PcdLib.h>
#include <Ppi/ArmMpCoreInfo.h>

// CPU topology
STATIC ARM_CORE_INFO mCoreInfo[] = {
    { 0x0, 0x0, 0x0 },  // Cluster 0, Core 0
    { 0x0, 0x0, 0x1 },  // Cluster 0, Core 1
    { 0x0, 0x0, 0x2 },  // Cluster 0, Core 2
    { 0x0, 0x0, 0x3 },  // Cluster 0, Core 3
};

// Memory map
STATIC ARM_MEMORY_REGION_DESCRIPTOR mVirtualMemoryTable[] = {
    // System RAM
    {
        ARM_VE_DRAM_BASE,
        ARM_VE_DRAM_BASE,
        ARM_VE_DRAM_SIZE,
        ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK
    },
    // GIC
    {
        PcdGet64(PcdGicDistributorBase),
        PcdGet64(PcdGicDistributorBase),
        SIZE_1MB,
        ARM_MEMORY_REGION_ATTRIBUTE_DEVICE
    },
    // UART
    {
        PcdGet64(PcdSerialRegisterBase),
        PcdGet64(PcdSerialRegisterBase),
        SIZE_4KB,
        ARM_MEMORY_REGION_ATTRIBUTE_DEVICE
    },
    // PCIe
    {
        PCIE_ECAM_BASE,
        PCIE_ECAM_BASE,
        PCIE_ECAM_SIZE,
        ARM_MEMORY_REGION_ATTRIBUTE_DEVICE
    },
    // End
    { 0, 0, 0, 0 }
};

RETURN_STATUS
ArmPlatformInitialize (
    IN UINTN  MpId
    )
{
    // Early platform initialization
    // Called before MMU is enabled

    // Platform-specific hardware init
    PlatformEarlyInit();

    return RETURN_SUCCESS;
}

VOID
ArmPlatformGetVirtualMemoryMap (
    OUT ARM_MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap
    )
{
    *VirtualMemoryMap = mVirtualMemoryTable;
}

EFI_STATUS
PrePeiCoreGetMpCoreInfo (
    OUT UINTN          *CoreCount,
    OUT ARM_CORE_INFO  **ArmCoreTable
    )
{
    *CoreCount = ARRAY_SIZE(mCoreInfo);
    *ArmCoreTable = mCoreInfo;
    return EFI_SUCCESS;
}

ARM_CORE_INFO *
ArmCoreInfoTable (
    OUT UINTN  *Count
    )
{
    *Count = ARRAY_SIZE(mCoreInfo);
    return mCoreInfo;
}

EFI_BOOT_MODE
ArmPlatformGetBootMode (
    VOID
    )
{
    // Detect boot mode from hardware
    return BOOT_WITH_FULL_CONFIGURATION;
}

SEC/PrePi Entry Point

// PrePi/PrePi.c

#include <Library/PrePiLib.h>
#include <Library/ArmPlatformLib.h>
#include <Library/SerialPortLib.h>

VOID
CEntryPoint (
    IN UINTN  MpId,
    IN UINTN  UefiMemoryBase
    )
{
    EFI_STATUS  Status;
    UINTN       StackBase;
    UINTN       StackSize;

    // Initialize serial first for debug output
    SerialPortInitialize();
    DEBUG ((DEBUG_INFO, "Platform UEFI starting...\n"));
    DEBUG ((DEBUG_INFO, "MpId: 0x%lx\n", MpId));

    // Initialize platform
    Status = ArmPlatformInitialize(MpId);
    ASSERT_EFI_ERROR(Status);

    // Enable caches
    ArmEnableDataCache();
    ArmEnableInstructionCache();

    // Set up stack
    StackBase = UefiMemoryBase;
    StackSize = PcdGet32(PcdCPUCorePrimaryStackSize);

    // Build memory HOBs
    BuildMemoryHobs();

    // Build CPU HOBs
    BuildCpuHob(ArmGetPhysicalAddressBits(), ArmGetVirtualAddressBits());

    // Build stack HOB
    BuildStackHob(StackBase, StackSize);

    // Build FV HOBs
    BuildFvHob(PcdGet64(PcdFvBaseAddress), PcdGet64(PcdFvSize));

    // Build HOB for DTB if present
    if (DeviceTreeBase != 0) {
        BuildGuidDataHob(&gFdtHobGuid, &DeviceTreeBase, sizeof(UINT64));
    }

    // Transfer to DXE
    LoadDxeCoreFromFv(NULL, 0);

    // Should not return
    CpuDeadLoop();
}

VOID
BuildMemoryHobs (
    VOID
    )
{
    // System memory
    BuildResourceDescriptorHob(
        EFI_RESOURCE_SYSTEM_MEMORY,
        EFI_RESOURCE_ATTRIBUTE_PRESENT |
        EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
        EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
        EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
        EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
        EFI_RESOURCE_ATTRIBUTE_TESTED,
        PcdGet64(PcdSystemMemoryBase),
        PcdGet64(PcdSystemMemorySize)
    );

    // Reserved for TF-A
    BuildMemoryAllocationHob(
        TFA_MEMORY_BASE,
        TFA_MEMORY_SIZE,
        EfiReservedMemoryType
    );

    // MMIO
    BuildResourceDescriptorHob(
        EFI_RESOURCE_MEMORY_MAPPED_IO,
        EFI_RESOURCE_ATTRIBUTE_PRESENT,
        MMIO_BASE,
        MMIO_SIZE
    );
}

Phase 3: Core Drivers

GIC Driver Configuration

// Drivers/PlatformDxe/Gic.c

EFI_STATUS
PlatformGicInit (
    VOID
    )
{
    // GICv3 specific initialization

    UINT64  GicDist = PcdGet64(PcdGicDistributorBase);
    UINT64  GicRedist = PcdGet64(PcdGicRedistributorsBase);
    UINT32  NumCpus = PcdGet32(PcdCoreCount);
    UINTN   i;

    // Initialize Distributor
    // - Enable Affinity Routing
    // - Configure SPI defaults
    MmioOr32(GicDist + GICD_CTLR, GICD_CTLR_ARE_S | GICD_CTLR_ARE_NS);

    // Initialize Redistributors for each CPU
    for (i = 0; i < NumCpus; i++) {
        UINT64 GicrBase = GicRedist + i * GICR_FRAME_SIZE;

        // Wake up redistributor
        MmioAnd32(GicrBase + GICR_WAKER, ~GICR_WAKER_PROCESSOR_SLEEP);

        // Wait for children to wake
        while (MmioRead32(GicrBase + GICR_WAKER) & GICR_WAKER_CHILDREN_ASLEEP);
    }

    // Enable Group 1 NS interrupts
    MmioOr32(GicDist + GICD_CTLR, GICD_CTLR_ENABLE_G1NS);

    return EFI_SUCCESS;
}

ACPI Table Installation

// AcpiTables/AcpiTables.c

EFI_STATUS
EFIAPI
AcpiTablesEntryPoint (
    IN EFI_HANDLE        ImageHandle,
    IN EFI_SYSTEM_TABLE  *SystemTable
    )
{
    EFI_STATUS             Status;
    EFI_ACPI_TABLE_PROTOCOL *AcpiTable;

    Status = gBS->LocateProtocol(
        &gEfiAcpiTableProtocolGuid,
        NULL,
        (VOID **)&AcpiTable
    );
    if (EFI_ERROR(Status)) {
        return Status;
    }

    // Install required tables
    UINTN TableKey;

    // MADT
    Status = AcpiTable->InstallAcpiTable(
        AcpiTable, &Madt, sizeof(Madt), &TableKey);
    ASSERT_EFI_ERROR(Status);

    // GTDT
    Status = AcpiTable->InstallAcpiTable(
        AcpiTable, &Gtdt, sizeof(Gtdt), &TableKey);
    ASSERT_EFI_ERROR(Status);

    // IORT
    Status = AcpiTable->InstallAcpiTable(
        AcpiTable, &Iort, sizeof(Iort), &TableKey);
    ASSERT_EFI_ERROR(Status);

    // PPTT
    Status = AcpiTable->InstallAcpiTable(
        AcpiTable, &Pptt, sizeof(Pptt), &TableKey);
    ASSERT_EFI_ERROR(Status);

    // SPCR
    Status = AcpiTable->InstallAcpiTable(
        AcpiTable, &Spcr, sizeof(Spcr), &TableKey);
    ASSERT_EFI_ERROR(Status);

    // DBG2
    Status = AcpiTable->InstallAcpiTable(
        AcpiTable, &Dbg2, Dbg2.Header.Length, &TableKey);
    ASSERT_EFI_ERROR(Status);

    // DSDT (installed via FADT reference)
    InstallDsdt(AcpiTable);

    return EFI_SUCCESS;
}

Phase 4: Validation

Boot Validation Checklist

## Validation Checklist

### Stage 1: Serial Output
- [ ] TF-A boot messages visible
- [ ] UEFI debug output visible
- [ ] No garbage/corruption on serial

### Stage 2: Memory
- [ ] Correct DRAM detected
- [ ] HOB list valid
- [ ] Memory map correct
- [ ] No memory corruption

### Stage 3: Interrupts
- [ ] GIC initialized
- [ ] Timer interrupts working
- [ ] Serial RX interrupt (optional)

### Stage 4: UEFI Shell
- [ ] Shell prompt appears
- [ ] `memmap` shows correct memory
- [ ] `dh` lists handles
- [ ] `drivers` shows loaded drivers

### Stage 5: ACPI
- [ ] `acpiview` shows all tables
- [ ] No FWTS ACPI errors
- [ ] Tables checksum valid

### Stage 6: OS Boot
- [ ] GRUB loads
- [ ] Kernel starts
- [ ] Root filesystem mounts
- [ ] Console works in Linux

### Stage 7: Compliance
- [ ] BSA ACS passes
- [ ] SCT test suite passes
- [ ] FWTS tests pass

Automated Validation Script

#!/bin/bash
# validate-platform.sh

set -e

PLATFORM="Platform/Vendor/PlatformPkg"
BUILD_DIR="Build/Platform/DEBUG_GCC5"

echo "=== Platform Validation ==="

# Build
echo "Building..."
build -a AARCH64 -t GCC5 -p $PLATFORM/PlatformPkg.dsc -b DEBUG

# Verify FD created
if [ ! -f "$BUILD_DIR/FV/PLATFORM.fd" ]; then
    echo "ERROR: FD not created"
    exit 1
fi
echo "FD created successfully"

# Check FD size
FD_SIZE=$(stat -c %s "$BUILD_DIR/FV/PLATFORM.fd")
echo "FD size: $FD_SIZE bytes"

# List included modules
echo "Modules in FV:"
$EDK_TOOLS_PATH/bin/VolInfo "$BUILD_DIR/FV/FVMAIN_COMPACT.fv" | grep -E "File Name|Type"

# Verify ACPI tables
echo "Checking ACPI tables..."
for table in Madt Gtdt Iort Pptt Spcr Dbg2; do
    if grep -q "$table" "$BUILD_DIR/AARCH64/AcpiTables/"; then
        echo "  $table: OK"
    else
        echo "  $table: MISSING"
    fi
done

echo "=== Validation Complete ==="

QEMU Testing

#!/bin/bash
# test-qemu.sh

FD_FILE="Build/Platform/DEBUG_GCC5/FV/PLATFORM.fd"

# Create flash images
dd if=/dev/zero of=flash0.img bs=64M count=1
dd if=/dev/zero of=flash1.img bs=64M count=1
dd if="$FD_FILE" of=flash0.img conv=notrunc

# Run QEMU
qemu-system-aarch64 \
    -M virt \
    -cpu cortex-a72 \
    -m 2G \
    -drive if=pflash,format=raw,file=flash0.img \
    -drive if=pflash,format=raw,file=flash1.img \
    -serial stdio \
    -net none \
    -d guest_errors \
    2>&1 | tee qemu.log

# Check for expected output
if grep -q "UEFI firmware starting" qemu.log; then
    echo "Boot started successfully"
fi

if grep -q "Shell>" qemu.log; then
    echo "Reached UEFI Shell"
fi

Common Porting Issues

Issue: No Serial Output

// Check UART initialization order
// Ensure UART is initialized before any DEBUG prints

// In PlatformLib.c
RETURN_STATUS
ArmPlatformInitialize (
    IN UINTN  MpId
    )
{
    // Initialize UART FIRST
    UINT64 UartBase = PcdGet64(PcdSerialRegisterBase);

    // Check if UART clock is enabled
    EnableUartClock();

    // Initialize UART
    Pl011UartInitialize(UartBase);

    // Now safe to use DEBUG
    DEBUG((DEBUG_INFO, "Platform Init\n"));

    return RETURN_SUCCESS;
}

Issue: Exception on Memory Access

// Ensure MMU is configured correctly
// Check memory regions are properly mapped

// Verify in ArmPlatformGetVirtualMemoryMap()
STATIC ARM_MEMORY_REGION_DESCRIPTOR mVirtualMemoryTable[] = {
    // All accessed regions must be mapped
    { DRAM_BASE, DRAM_BASE, DRAM_SIZE, ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK },
    { GIC_BASE, GIC_BASE, GIC_SIZE, ARM_MEMORY_REGION_ATTRIBUTE_DEVICE },
    { UART_BASE, UART_BASE, UART_SIZE, ARM_MEMORY_REGION_ATTRIBUTE_DEVICE },
    // ... all other regions
    { 0, 0, 0, 0 }
};

Issue: Timer Not Working

// Verify timer frequency and interrupts
DEBUG((DEBUG_INFO, "Timer freq: %lu Hz\n", ArmGenericTimerGetTimerFreq()));

// Ensure timer interrupts are routed correctly
// PPIs 29, 30, 27, 26 for secure, NS, virtual, hyp timers

// Check GIC SPI/PPI routing
GicV3EnableInterruptSource(30);  // NS physical timer

Production Hardening

## Production Checklist

### Security
- [ ] Remove DEBUG prints in RELEASE build
- [ ] Disable serial console (or protect)
- [ ] Enable Secure Boot
- [ ] Validate TF-A chain of trust
- [ ] Lock flash write protection

### Stability
- [ ] Stress test with multiple reboots
- [ ] Test all boot paths (cold, warm, S3)
- [ ] Memory test full DRAM
- [ ] Test with various OS versions

### Compliance
- [ ] Pass BSA ACS at target level
- [ ] Pass SCT with >95% pass rate
- [ ] Pass FWTS with no critical failures
- [ ] SystemReady IR/ES/SR certification

### Documentation
- [ ] Platform configuration documented
- [ ] Build instructions complete
- [ ] Known issues documented
- [ ] Release notes prepared

References


This concludes Chapter 23: ARM UEFI Development. Return to Chapter Index or continue to Part 5: Practical Projects.


Back to top

UEFI Development Guide is not affiliated with the UEFI Forum. Content is provided for educational purposes.

This site uses Just the Docs, a documentation theme for Jekyll.