POST Code Monitoring

Capture, store, and expose host POST codes through the OpenBMC stack, from LPC snoop hardware to Redfish APIs.

Table of Contents

  1. Overview
  2. Architecture
    1. POST Code Capture Pipeline
    2. D-Bus Interfaces
    3. Key Dependencies
  3. Setup and Configuration
    1. Build-Time Configuration (Yocto)
    2. Kernel and Device Tree Configuration
    3. Runtime Verification
  4. Capturing POST Codes
    1. How LPC Snoop Works
    2. Reading POST Codes via D-Bus
    3. Querying POST Code History
  5. Redfish POST Code Exposure
    1. PostCodes LogService
    2. Entry Format
    3. Example Redfish Response
    4. Clearing POST Code Logs
  6. Boot Progress State Mapping
    1. BootProgress D-Bus Property
    2. Standard Boot Progress States
    3. Boot Progress via Redfish
    4. Customizing Boot Progress Mapping
  7. Multi-Host POST Code Collection
    1. Multi-Host Architecture
    2. Yocto Configuration for Multi-Host
    3. Multi-Host D-Bus Paths
    4. Device Tree for Multi-Host
  8. Troubleshooting
    1. No POST Codes Appearing
    2. POST Code History Missing
    3. Redfish PostCodes Endpoint Returns 404
    4. POST Codes Stop After Boot
  9. Examples
  10. References
    1. OpenBMC Repositories
    2. Specifications
    3. Related Guides

Overview

POST codes (Power-On Self-Test codes) are single-byte or multi-byte values that the host firmware writes to I/O port 0x80 during boot. Each code indicates which initialization stage the BIOS or UEFI firmware has reached. When a system hangs during boot, the last POST code captured by the BMC tells you exactly where the host stalled.

OpenBMC provides a complete POST code pipeline. The LPC snoop hardware on the ASPEED BMC captures every write to port 0x80, the postd daemon reads those values from the kernel driver, phosphor-post-code-manager stores them organized by boot cycle, and bmcweb exposes the data through standard Redfish LogService endpoints. This pipeline gives operators full visibility into host boot progress without requiring physical seven-segment displays or serial console access.

You use POST code monitoring whenever you need to diagnose host boot failures, track boot progress remotely, or integrate boot telemetry into data center management workflows. Combined with the BootProgress D-Bus property, POST codes provide both fine-grained numeric codes and human-readable boot stage descriptions.

Key concepts covered:

  • LPC snoop capture and the kernel aspeed-lpc-snoop driver
  • The postd and phosphor-post-code-manager daemons
  • Redfish POST code exposure via PostCodes LogService
  • Boot progress state mapping through D-Bus properties
  • Multi-host POST code collection

Architecture

POST Code Capture Pipeline

The POST code pipeline flows from hardware capture to Redfish exposure through four stages.

+------------------------------------------------------------------+
|                  POST Code Capture Pipeline                      |
+------------------------------------------------------------------+
|                                                                  |
|  +-------------------+                                           |
|  | Host CPU / BIOS   |  Writes POST codes to I/O port 0x80       |
|  +--------+----------+                                           |
|           |  LPC bus                                             |
|           v                                                      |
|  +-------------------+                                           |
|  | ASPEED LPC Snoop  |  Hardware captures port 0x80 writes       |
|  | (aspeed-lpc-snoop)|  Kernel driver: /dev/aspeed-lpc-snoop0    |
|  +--------+----------+                                           |
|           |  Character device read                               |
|           v                                                      |
|  +-------------------+                                           |
|  | postd             |  Reads raw bytes from snoop device        |
|  | (snoop daemon)    |  Publishes to D-Bus: State.Boot.Raw       |
|  +--------+----------+                                           |
|           |  D-Bus PropertiesChanged signal                      |
|           v                                                      |
|  +-------------------+                                           |
|  | phosphor-post-    |  Stores codes indexed by boot cycle       |
|  | code-manager      |  Persists history across BMC reboots      |
|  +--------+----------+                                           |
|           |  D-Bus object tree                                   |
|           v                                                      |
|  +-------------------+                                           |
|  | bmcweb            |  Exposes via Redfish:                     |
|  | (Redfish server)  |  /redfish/v1/.../LogServices/PostCodes    |
|  +-------------------+                                           |
|                                                                  |
+------------------------------------------------------------------+

D-Bus Interfaces

Interface Object Path Description
xyz.openbmc_project.State.Boot.Raw /xyz/openbmc_project/state/boot/raw0 Current POST code value
xyz.openbmc_project.State.Boot.PostCode /xyz/openbmc_project/State/Boot/PostCode0 POST code history by boot cycle
xyz.openbmc_project.State.Boot.Progress /xyz/openbmc_project/state/host0 High-level boot progress state

Key Dependencies

  • aspeed-lpc-snoop kernel driver: Captures LPC port 0x80 writes in hardware
  • phosphor-host-postd: Reads the snoop device and publishes to D-Bus
  • phosphor-post-code-manager: Aggregates and persists POST code history
  • bmcweb: Translates D-Bus POST code objects into Redfish responses

Setup and Configuration

Build-Time Configuration (Yocto)

# In your machine .conf or local.conf

# Include POST code packages
IMAGE_INSTALL:append = " \
    phosphor-host-postd \
    phosphor-post-code-manager \
"

# The LPC snoop driver is typically built into the kernel
# for ASPEED platforms. Verify it is enabled:
KERNEL_FEATURES:append = " features/aspeed/lpc-snoop.scc"

Kernel and Device Tree Configuration

Ensure the ASPEED LPC snoop driver is enabled in your kernel (CONFIG_ASPEED_LPC_SNOOP=y) and the snoop node is enabled in your platform device tree:

&lpc_snoop {
    status = "okay";
    snoop-ports = <0x80>;
};

Most ASPEED reference platforms (ast2500-evb, ast2600-evb) already have the LPC snoop node enabled. Check your platform DTS before adding a duplicate entry.

Runtime Verification

# Verify the snoop device exists
ls -l /dev/aspeed-lpc-snoop0

# Check postd service
systemctl status phosphor-host-postd

# Check post-code-manager service
systemctl status phosphor-post-code-manager

# View service logs
journalctl -u phosphor-host-postd -f
journalctl -u phosphor-post-code-manager -f

Capturing POST Codes

How LPC Snoop Works

The ASPEED BMC includes dedicated hardware that monitors the LPC bus for writes to specific I/O port addresses. When the host writes a byte to port 0x80, the snoop hardware latches the value into a FIFO buffer. The kernel driver exposes this FIFO as a character device at /dev/aspeed-lpc-snoop0.

The postd daemon performs a blocking read on this device. Each time a new POST code arrives, postd updates the Value property on the xyz.openbmc_project.State.Boot.Raw D-Bus interface. The phosphor-post-code-manager daemon monitors this property via D-Bus signal matching and appends each new code to the current boot cycle’s history.

Reading POST Codes via D-Bus

# Get the current (most recent) POST code
busctl get-property xyz.openbmc_project.State.Boot.Raw \
    /xyz/openbmc_project/state/boot/raw0 \
    xyz.openbmc_project.State.Boot.Raw \
    Value

# Watch POST codes arrive in real time
busctl monitor xyz.openbmc_project.State.Boot.Raw

Querying POST Code History

The post-code-manager stores codes organized by boot cycle number. Boot cycle 1 is the most recent complete boot, cycle 2 is the one before that, and so on.

# Get POST codes from the current boot cycle
busctl call xyz.openbmc_project.State.Boot.PostCode0 \
    /xyz/openbmc_project/State/Boot/PostCode0 \
    xyz.openbmc_project.State.Boot.PostCode \
    GetPostCodesWithTimeStamp q 1

# Get the number of stored boot cycles
busctl get-property xyz.openbmc_project.State.Boot.PostCode0 \
    /xyz/openbmc_project/State/Boot/PostCode0 \
    xyz.openbmc_project.State.Boot.PostCode \
    CurrentBootCycleCount

The GetPostCodesWithTimeStamp method returns an array of (timestamp, code) pairs. The timestamp is a microsecond-precision value that lets you calculate the time between boot stages.


Redfish POST Code Exposure

PostCodes LogService

OpenBMC exposes POST codes through the Redfish LogService at the standard path. This is the primary interface for remote management tools.

# Get the PostCodes LogService
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/Systems/system/LogServices/PostCodes

# List POST code entries
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/Systems/system/LogServices/PostCodes/Entries

# Get a specific entry
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/Systems/system/LogServices/PostCodes/Entries/B1-1

Entry Format

Each Redfish POST code entry includes:

Field Description Example
Id Boot cycle and sequence index B1-1 (Boot 1, code 1)
MessageId Redfish message identifier OpenBMC.0.2.BIOSPOSTCode
Created Timestamp of the POST code 2026-02-06T10:15:30+00:00
MessageArgs Array containing the POST code value ["0x19"]
Severity Always OK for POST codes OK

Example Redfish Response

{
    "@odata.id": "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/B1-3",
    "@odata.type": "#LogEntry.v1_9_0.LogEntry",
    "Id": "B1-3",
    "Name": "POST Code Log Entry",
    "EntryType": "Event",
    "Severity": "OK",
    "Created": "2026-02-06T10:15:32.451+00:00",
    "MessageId": "OpenBMC.0.2.BIOSPOSTCode",
    "MessageArgs": [
        "0xA2"
    ],
    "Message": "BIOS POST Code: 0xA2"
}

Clearing POST Code Logs

# Clear all POST code entries
curl -k -u root:0penBmc -X POST \
    https://localhost/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog

Clearing POST code logs deletes all stored boot cycle history. This action cannot be undone. Consider exporting log data before clearing if you need it for later analysis.


Boot Progress State Mapping

BootProgress D-Bus Property

In addition to raw numeric POST codes, OpenBMC maps host boot stages to human-readable progress states. The phosphor-state-manager exposes a BootProgress property that higher-level tools can use without needing to interpret vendor-specific POST code tables.

# Get current boot progress
busctl get-property xyz.openbmc_project.State.Host \
    /xyz/openbmc_project/state/host0 \
    xyz.openbmc_project.State.Boot.Progress \
    BootProgress

Standard Boot Progress States

D-Bus Enumeration Description Typical POST Code Range
Unspecified Boot state unknown or not yet started
PrimaryProcInit Primary processor initialization 0x01 - 0x0F
BusInit System bus (PCI, USB) initialization 0x10 - 0x2F
MemoryInit Memory detection and training 0x30 - 0x4F
SecondaryProcInit Secondary processor initialization 0x50 - 0x5F
PCIInit PCI resource enumeration and configuration 0x60 - 0x7F
OSStart Operating system handoff beginning 0x80 - 0x8F
OSRunning Operating system is running 0x90+
SystemInitComplete All firmware initialization complete 0xA0 - 0xAF
SystemSetup BIOS setup / configuration menu active 0xB0 - 0xBF

POST code-to-progress-state mappings are vendor-specific. The ranges listed above are common conventions, but your BIOS vendor may use different assignments. Consult your BIOS documentation for exact mappings.

Boot Progress via Redfish

The boot progress state is also available through the Redfish Systems resource:

# Query boot progress through Redfish
curl -k -u root:0penBmc \
    https://localhost/redfish/v1/Systems/system | \
    python3 -m json.tool | grep -A 5 BootProgress

Example response fragment:

{
    "BootProgress": {
        "LastState": "SystemHardwareInitializationComplete",
        "LastStateTime": "2026-02-06T10:16:45+00:00"
    }
}

Customizing Boot Progress Mapping

To map your platform’s POST codes to standard boot progress states, create a platform-specific configuration in your machine layer:

{
    "CodeMap": {
        "0x13": "PrimaryProcInit",
        "0x34": "MemoryInit",
        "0x62": "PCIInit",
        "0x85": "OSStart",
        "0xA0": "SystemInitComplete"
    }
}

Multi-Host POST Code Collection

Multi-Host Architecture

In multi-host (multi-node) platforms, each host has an independent POST code pipeline. The BMC manages separate snoop devices, postd instances, and post-code-manager instances for each host. Each pipeline follows the same four-stage flow described in the Architecture section, with instance-numbered D-Bus paths and Redfish endpoints.

Yocto Configuration for Multi-Host

# Enable multi-host POST code support
# In your machine .conf
OBMC_HOST_INSTANCES = "0 1 2 3"

# Each instance gets its own systemd service
# phosphor-host-postd@0.service
# phosphor-host-postd@1.service
# etc.

Multi-Host D-Bus Paths

Each host instance uses a numbered suffix on D-Bus paths. Replace N with the host index (0, 1, 2, …):

Resource D-Bus Path
Current POST code /xyz/openbmc_project/state/boot/rawN
POST code history /xyz/openbmc_project/State/Boot/PostCodeN
Boot progress /xyz/openbmc_project/state/hostN
# Read Host 1 current POST code
busctl get-property xyz.openbmc_project.State.Boot.Raw \
    /xyz/openbmc_project/state/boot/raw1 \
    xyz.openbmc_project.State.Boot.Raw Value

# Read Host 1 boot cycle history
busctl call xyz.openbmc_project.State.Boot.PostCode1 \
    /xyz/openbmc_project/State/Boot/PostCode1 \
    xyz.openbmc_project.State.Boot.PostCode \
    GetPostCodesWithTimeStamp q 1

Device Tree for Multi-Host

&lpc_snoop {
    status = "okay";
    snoop-ports = <0x80 0x81>;
    /* Port 0x80 -> /dev/aspeed-lpc-snoop0 (Host 0) */
    /* Port 0x81 -> /dev/aspeed-lpc-snoop1 (Host 1) */
};

Some multi-host platforms use separate LPC buses rather than separate I/O ports. In that case, each LPC bus has its own snoop node in the device tree. Check your platform’s hardware design to determine the correct configuration.


Troubleshooting

No POST Codes Appearing

Symptom: The Value property on State.Boot.Raw never changes, even when the host is booting.

Solution:

# 1. Verify the snoop device exists
ls -l /dev/aspeed-lpc-snoop*

# 2. Check the kernel driver is loaded
dmesg | grep -i snoop

# 3. Verify postd is running and connected
systemctl status phosphor-host-postd
journalctl -u phosphor-host-postd --no-pager -n 20

# 4. Read the snoop device directly (bypasses postd)
# This blocks until a POST code arrives
xxd /dev/aspeed-lpc-snoop0

# 5. Check the device tree has snoop enabled
cat /sys/firmware/devicetree/base/ahb/apb/lpc/lpc-snoop/status

If xxd /dev/aspeed-lpc-snoop0 produces no output even during host boot, the issue is at the hardware or kernel driver level. Verify that the LPC bus is physically connected and the host is actually writing to port 0x80.

POST Code History Missing

Symptom: Real-time POST codes appear in D-Bus but GetPostCodesWithTimeStamp returns empty results.

Solution:

# 1. Check post-code-manager service
systemctl status phosphor-post-code-manager
journalctl -u phosphor-post-code-manager --no-pager -n 20

# 2. Check persistent storage
ls -la /var/lib/phosphor-post-code-manager/

Redfish PostCodes Endpoint Returns 404

Symptom: Querying /redfish/v1/Systems/system/LogServices/PostCodes returns a 404 error.

Solution:

# 1. Verify bmcweb is running
systemctl status bmcweb

# 2. Check that post-code-manager D-Bus objects exist
busctl tree xyz.openbmc_project.State.Boot.PostCode0

# 3. Confirm bmcweb was built with POST code support
# The PostCodes LogService requires BMCWEB_ENABLE_REDFISH_POSTCODE

POST Codes Stop After Boot

This is usually normal behavior. Most BIOS implementations stop writing to port 0x80 once they hand off to the OS bootloader.


Examples

Working examples are available in the examples/post-code directory:

  • read-postcode.sh - Read current and historical POST codes via D-Bus
  • monitor-boot.sh - Monitor POST codes and boot progress in real time
  • redfish-postcode.sh - Query POST code history through Redfish API

References

OpenBMC Repositories

Specifications


Tested on: OpenBMC master, QEMU ast2600-evb. Multi-host features require platform-specific hardware support.


Back to top

OpenBMC Guide Tutorial is not affiliated with the OpenBMC project. Content is provided for educational purposes.

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