Section 23.5: Platform Configuration
ARM platform configuration involves PCDs, memory mapping, GIC setup, and peripheral initialization. This section covers the key configuration areas for ARM UEFI platforms.
Platform Configuration Database (PCD)
Essential ARM PCDs
# Platform DSC file - [PcdsFixedAtBuild] section
[PcdsFixedAtBuild.common]
#
# System Memory Configuration
#
gArmTokenSpaceGuid.PcdSystemMemoryBase|0x80000000
gArmTokenSpaceGuid.PcdSystemMemorySize|0x100000000 # 4GB
#
# CPU Configuration
#
gArmTokenSpaceGuid.PcdArmPrimaryCoreMask|0x0
gArmTokenSpaceGuid.PcdArmPrimaryCore|0x0
gArmTokenSpaceGuid.PcdCpuVectorBaseAddress|0x00000000
#
# GIC Configuration
#
gArmTokenSpaceGuid.PcdGicDistributorBase|0x08000000
gArmTokenSpaceGuid.PcdGicRedistributorsBase|0x080A0000
gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x08010000
#
# Generic Timer
#
gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum|29
gArmTokenSpaceGuid.PcdArmArchTimerIntrNum|30
gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|27
gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|26
gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz|100000000 # 100MHz
#
# UART Configuration
#
gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0x09000000
gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200
gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits|8
gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity|1
gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits|1
Memory Map PCDs
[PcdsFixedAtBuild.common]
#
# UEFI Memory Regions
#
# FD (Firmware Device) location
gArmTokenSpaceGuid.PcdFdBaseAddress|0x00000000
gArmTokenSpaceGuid.PcdFdSize|0x00400000 # 4MB
# FV (Firmware Volume) location
gArmTokenSpaceGuid.PcdFvBaseAddress|0x00000000
gArmTokenSpaceGuid.PcdFvSize|0x00400000
# Stack configuration
gArmPlatformTokenSpaceGuid.PcdCPUCorePrimaryStackSize|0x10000
# Reserved regions
gArmTokenSpaceGuid.PcdTrustedFirmwareMemoryBase|0x04000000
gArmTokenSpaceGuid.PcdTrustedFirmwareMemorySize|0x01000000
# MMIO Regions (for resource descriptors)
gArmTokenSpaceGuid.PcdPciIoBase|0x00000000
gArmTokenSpaceGuid.PcdPciIoSize|0x00010000
gArmTokenSpaceGuid.PcdPciMmio32Base|0x10000000
gArmTokenSpaceGuid.PcdPciMmio32Size|0x2EFF0000
gArmTokenSpaceGuid.PcdPciMmio64Base|0x8000000000
gArmTokenSpaceGuid.PcdPciMmio64Size|0x8000000000
Dynamic PCDs
[PcdsDynamicDefault.common]
#
# Boot configuration (can be changed at runtime)
#
gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|3
#
# ConOut/ConIn configuration
#
gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow|0
gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn|0
gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution|1920
gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution|1080
Memory Map Configuration
Memory Region Types
// Platform memory map definition
// PlatformLib.c
#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 16
ARM_MEMORY_REGION_DESCRIPTOR VirtualMemoryTable[] = {
// System RAM
{
PcdGet64(PcdSystemMemoryBase), // Base
PcdGet64(PcdSystemMemoryBase), // Virtual (same for 1:1)
PcdGet64(PcdSystemMemorySize), // Length
ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK // Attributes
},
// Firmware Volume (Flash)
{
PcdGet64(PcdFdBaseAddress),
PcdGet64(PcdFdBaseAddress),
PcdGet64(PcdFdSize),
ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK_RO
},
// GIC Distributor
{
PcdGet64(PcdGicDistributorBase),
PcdGet64(PcdGicDistributorBase),
SIZE_64KB,
ARM_MEMORY_REGION_ATTRIBUTE_DEVICE
},
// GIC Redistributors
{
PcdGet64(PcdGicRedistributorsBase),
PcdGet64(PcdGicRedistributorsBase),
SIZE_1MB,
ARM_MEMORY_REGION_ATTRIBUTE_DEVICE
},
// UART
{
PcdGet64(PcdSerialRegisterBase),
PcdGet64(PcdSerialRegisterBase),
SIZE_4KB,
ARM_MEMORY_REGION_ATTRIBUTE_DEVICE
},
// PCIe ECAM
{
PCIE_ECAM_BASE,
PCIE_ECAM_BASE,
PCIE_ECAM_SIZE,
ARM_MEMORY_REGION_ATTRIBUTE_DEVICE
},
// PCIe MMIO
{
PCIE_MMIO_BASE,
PCIE_MMIO_BASE,
PCIE_MMIO_SIZE,
ARM_MEMORY_REGION_ATTRIBUTE_DEVICE
},
// End of table
{ 0, 0, 0, 0 }
};
VOID
ArmPlatformGetVirtualMemoryMap (
OUT ARM_MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap
)
{
*VirtualMemoryMap = VirtualMemoryTable;
}
Memory Attributes
// Memory region attributes
typedef enum {
// Device memory (non-cacheable, non-bufferable)
ARM_MEMORY_REGION_ATTRIBUTE_DEVICE = 0,
// Normal memory - Uncached
ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED,
// Normal memory - Write-Through
ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH,
// Normal memory - Write-Back (default for RAM)
ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK,
// Read-Only variants
ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK_RO,
ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH_RO,
// Execute-Never variants
ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK_XN,
ARM_MEMORY_REGION_ATTRIBUTE_DEVICE_XN,
} ARM_MEMORY_REGION_ATTRIBUTES;
GIC Configuration
GICv3 Initialization
// GIC Driver - GicV3/GicV3Dxe.c
EFI_STATUS
EFIAPI
GicV3Initialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINTN GicDistributorBase;
UINTN GicRedistributorBase;
GicDistributorBase = PcdGet64(PcdGicDistributorBase);
GicRedistributorBase = PcdGet64(PcdGicRedistributorsBase);
// 1. Initialize Distributor
GicV3DistributorInit(GicDistributorBase);
// 2. Initialize Redistributor for BSP
GicV3ReDistributorInit(GicRedistributorBase);
// 3. Initialize CPU interface
GicV3CpuIfInit();
// 4. Install Hardware Interrupt Protocol
return InstallAndRegisterInterruptProtocol();
}
STATIC
VOID
GicV3DistributorInit (
IN UINTN GicDistributorBase
)
{
UINT32 NumIt;
UINT32 Index;
// Wait for RWP to clear
GicV3WaitForRwp(GicDistributorBase);
// Get number of interrupt lines
NumIt = MmioRead32(GicDistributorBase + GICD_TYPER);
NumIt = ((NumIt & 0x1F) + 1) * 32;
// Disable all interrupts
for (Index = 0; Index < (NumIt / 32); Index++) {
MmioWrite32(
GicDistributorBase + GICD_ICENABLER + (Index * 4),
0xFFFFFFFF
);
}
// Set all SPIs to Group 1 Non-Secure
for (Index = 1; Index < (NumIt / 32); Index++) {
MmioWrite32(
GicDistributorBase + GICD_IGROUPR + (Index * 4),
0xFFFFFFFF
);
}
// Enable Affinity Routing, ARE_S and ARE_NS
MmioOr32(GicDistributorBase + GICD_CTLR,
GICD_CTLR_ARE_S | GICD_CTLR_ARE_NS);
// Enable Group 1 Non-Secure interrupts
MmioOr32(GicDistributorBase + GICD_CTLR,
GICD_CTLR_ENABLE_GRP1_NS);
}
STATIC
VOID
GicV3CpuIfInit (
VOID
)
{
// Set priority mask (allow all priorities)
ArmGicV3SetPriorityMask(0xFF);
// Set Binary Point Register
ArmGicV3SetBinaryPointer(0);
// Enable Group 1 Non-Secure for EL1
ArmGicV3EnableInterruptInterface();
}
Interrupt Routing Configuration
// Configure interrupt routing for specific SPI
EFI_STATUS
ConfigureInterrupt (
IN UINTN IntId,
IN UINTN Priority,
IN UINTN TargetCpu
)
{
UINTN GicDistributorBase = PcdGet64(PcdGicDistributorBase);
UINT64 Mpidr;
// Get target CPU's MPIDR for affinity routing
Mpidr = GetCpuMpidr(TargetCpu);
// Configure priority
MmioWrite8(
GicDistributorBase + GICD_IPRIORITYR + IntId,
(UINT8)Priority
);
// Configure affinity routing (GICv3)
MmioWrite64(
GicDistributorBase + GICD_IROUTER + (IntId * 8),
Mpidr & 0xFF00FFFFFF // Aff0, Aff1, Aff2, Aff3
);
// Configure as edge or level triggered
GicV3SetTriggerType(IntId, TRIGGER_LEVEL);
// Enable the interrupt
GicV3EnableInterrupt(IntId);
return EFI_SUCCESS;
}
Timer Configuration
Generic Timer Setup
// Platform timer configuration
EFI_STATUS
EFIAPI
TimerInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINT64 TimerFreq;
UINT32 TimerHypIntr;
UINT32 TimerSecIntr;
UINT32 TimerIntr;
UINT32 TimerVirtIntr;
// Get timer frequency
TimerFreq = ArmGenericTimerGetTimerFreq();
// Verify frequency matches PCD
if (TimerFreq != PcdGet64(PcdArmArchTimerFreqInHz)) {
DEBUG((DEBUG_WARN, "Timer frequency mismatch!\n"));
}
// Get interrupt numbers from PCDs
TimerHypIntr = PcdGet32(PcdArmArchTimerHypIntrNum);
TimerSecIntr = PcdGet32(PcdArmArchTimerSecIntrNum);
TimerIntr = PcdGet32(PcdArmArchTimerIntrNum);
TimerVirtIntr = PcdGet32(PcdArmArchTimerVirtIntrNum);
// Register timer interrupt handler
Status = gInterrupt->RegisterInterruptSource(
gInterrupt,
TimerIntr,
TimerInterruptHandler
);
// Enable timer interrupt
Status = gInterrupt->EnableInterruptSource(
gInterrupt,
TimerIntr
);
return Status;
}
Watchdog Configuration
// SBSA Generic Watchdog
#define WATCHDOG_CONTROL_BASE 0x09050000
#define WATCHDOG_REFRESH_BASE 0x09060000
#define WDOG_CTRL_ENABLE BIT0
#define WDOG_CTRL_INTR_ENABLE BIT1
EFI_STATUS
WatchdogInitialize (
IN UINT32 TimeoutMs
)
{
UINT64 TimerFreq;
UINT64 WatchdogValue;
TimerFreq = ArmGenericTimerGetTimerFreq();
WatchdogValue = (TimerFreq * TimeoutMs) / 1000;
// Set watchdog offset
MmioWrite32(WATCHDOG_CONTROL_BASE + WDOG_WOR, WatchdogValue);
// Enable watchdog
MmioWrite32(WATCHDOG_CONTROL_BASE + WDOG_WCS,
WDOG_CTRL_ENABLE);
return EFI_SUCCESS;
}
VOID
WatchdogRefresh (
VOID
)
{
// Writing any value refreshes the watchdog
MmioWrite32(WATCHDOG_REFRESH_BASE + WDOG_WRR, 1);
}
Serial Console Configuration
PL011 UART Setup
// PL011 UART initialization
#define PL011_UARTCR_UARTEN BIT0
#define PL011_UARTCR_TXE BIT8
#define PL011_UARTCR_RXE BIT9
EFI_STATUS
Pl011UartInitialize (
IN UINTN UartBase,
IN UINT32 ClockHz,
IN UINT32 BaudRate
)
{
UINT32 Divider;
UINT32 IntPart;
UINT32 FracPart;
// Disable UART
MmioWrite32(UartBase + UARTCR, 0);
// Set baud rate
// Divider = Clock / (16 * BaudRate)
Divider = (ClockHz * 4) / BaudRate;
IntPart = Divider >> 6;
FracPart = Divider & 0x3F;
MmioWrite32(UartBase + UARTIBRD, IntPart);
MmioWrite32(UartBase + UARTFBRD, FracPart);
// Configure: 8-bit, no parity, 1 stop, FIFO enabled
MmioWrite32(UartBase + UARTLCR_H,
PL011_UARTLCR_H_WLEN_8 | PL011_UARTLCR_H_FEN);
// Enable UART, TX, RX
MmioWrite32(UartBase + UARTCR,
PL011_UARTCR_UARTEN |
PL011_UARTCR_TXE |
PL011_UARTCR_RXE);
return EFI_SUCCESS;
}
SPCR Table Generation
// Serial Port Console Redirection Table
STATIC
EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE Spcr = {
.Header = {
.Signature = EFI_ACPI_6_3_SPCR_SIGNATURE,
.Length = sizeof(EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE),
.Revision = 2,
},
.InterfaceType = EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_ARM_PL011,
.BaseAddress = {
.AddressSpaceId = EFI_ACPI_6_3_SYSTEM_MEMORY,
.RegisterBitWidth = 32,
.RegisterBitOffset = 0,
.AccessSize = EFI_ACPI_6_3_DWORD,
.Address = UART_BASE_ADDRESS,
},
.InterruptType = EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_GIC,
.Irq = 0, // Not used for GIC
.GlobalSystemInterrupt = UART_INTERRUPT,
.BaudRate = EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_115200,
.Parity = EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_PARITY_NO_PARITY,
.StopBits = EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_STOP_BITS_1,
.FlowControl = 0,
.TerminalType = EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_VT_UTF8,
.PciDeviceId = 0xFFFF,
.PciVendorId = 0xFFFF,
};
PCIe Configuration
ECAM Configuration
// PCIe ECAM (Enhanced Configuration Access Mechanism)
#define PCIE_ECAM_BASE 0x4010000000ULL
#define PCIE_ECAM_SIZE 0x10000000ULL // 256MB for 256 buses
#define PCIE_SEGMENT 0
// PCI Express configuration
[PcdsFixedAtBuild.common]
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0x4010000000
gArmTokenSpaceGuid.PcdPciBusMin|0
gArmTokenSpaceGuid.PcdPciBusMax|255
// MCFG table for ECAM
STATIC
EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER Mcfg = {
.Header = {
.Signature = EFI_ACPI_6_3_MCFG_SIGNATURE,
.Length = sizeof(Mcfg) + sizeof(EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE),
.Revision = 1,
},
};
EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE McfgEntry = {
.BaseAddress = PCIE_ECAM_BASE,
.PciSegmentGroupNumber = PCIE_SEGMENT,
.StartBusNumber = 0,
.EndBusNumber = 255,
};
Root Complex Configuration
// PCIe Root Complex initialization
EFI_STATUS
PciHostBridgeInit (
VOID
)
{
// 1. Configure SMMU for PCIe (if present)
SmmuConfigurePcie();
// 2. Enable root complex
MmioOr32(PCIE_RC_BASE + RC_CONTROL, RC_ENABLE);
// 3. Configure memory windows
ConfigurePcieMemoryWindows();
// 4. Wait for link training
while (!(MmioRead32(PCIE_RC_BASE + RC_LINK_STATUS) & LINK_UP)) {
// Timeout handling
}
// 5. Bus enumeration happens via PciHostBridgeDxe
return EFI_SUCCESS;
}
Platform Initialization Sequence
sequenceDiagram
participant PrePi as PrePi Module
participant PlatLib as Platform Lib
participant GIC as GIC Driver
participant Timer as Timer Driver
participant PCI as PCIe Driver
PrePi->>PlatLib: ArmPlatformInitialize()
PlatLib->>PlatLib: Early UART init
PlatLib->>PlatLib: Configure MMU
PlatLib->>PlatLib: Build HOBs
Note over GIC: DXE Phase
GIC->>GIC: GicV3Initialize()
GIC->>GIC: Configure Distributor
GIC->>GIC: Configure Redistributor
GIC->>GIC: Enable interrupts
Timer->>Timer: TimerInitialize()
Timer->>Timer: Configure Generic Timer
Timer->>Timer: Register interrupt
PCI->>PCI: PciHostBridgeInit()
PCI->>PCI: Configure ECAM
PCI->>PCI: Bus enumeration
Platform Configuration Checklist
## ARM Platform Configuration Checklist
### Memory Map
- [ ] System RAM base and size
- [ ] Flash/FD location
- [ ] Reserved memory for TF-A
- [ ] MMIO regions for peripherals
- [ ] PCIe memory windows
### GIC
- [ ] Distributor base address
- [ ] Redistributor base address
- [ ] CPU interface configuration
- [ ] Interrupt routing
### Timer
- [ ] Timer frequency
- [ ] Timer interrupt numbers
- [ ] Watchdog configuration
### Serial Console
- [ ] UART base address
- [ ] UART clock frequency
- [ ] Baud rate settings
- [ ] SPCR table
### PCIe (if present)
- [ ] ECAM base address
- [ ] Bus range
- [ ] Memory windows (32-bit and 64-bit)
- [ ] MCFG table
### ACPI Tables
- [ ] All required tables configured
- [ ] Correct hardware addresses
- [ ] Valid interrupt mappings
References
Next: Section 23.6: Device Tree & ACPI - Hardware description for ARM platforms.