MSI PRO B850-P coreboot port: Phoenix openSIL AM5 IP block porting

Introduction

This blog post continues the MSI PRO B850-P coreboot porting series. In Part 1 we brought up the bootblock and romstage, mapped all USB, SATA, and PCIe ports. In Part 2 we added the USB and PCIe devicetree descriptors and integrated Phoenix openSIL as a submodule, reaching CCX initialization successfully - but the platform stalled during PCIe initialization because the Phoenix PoC openSIL was written for mobile CPUs, not the desktop AM5 variant used on the B850-P.

This post covers the work done to adapt Phoenix openSIL to the AM5 desktop platform. The relevant coreboot changes are tracked in pull request 870 on the Dasharo coreboot downstream repository and the openSIL changes in pull request 1 on 3mdeb openSIL downstream repository. The milestones covered in this post are:

Task 6. Port Phoenix AM5 specific code to openSIL:

  • Milestone c. Cover Phoenix mobile and desktop silicon initialization differences in openSIL (NBIO, SMU, GFX)

    Most of the code is similar or identical between desktop and mobile parts. However, care must be taken for possible small differences. The goal is to analyze and compare the desktop and mobile differences. This milestone covers NBIO, SMU and GFX blocks.

  • Milestone e. Cover Phoenix mobile and desktop silicon initialization differences in openSIL (MPIO, CXL)

    Most of the code is similar or identical between desktop and mobile parts. However, care must be taken for possible small differences. The goal is to analyze and compare the desktop and mobile differences. This milestone covers MPIO and CXL blocks.

A note on code generalization in coreboot

A substantial portion of the work in coreboot in this phase was not writing new code from scratch, but generalizing code that had already been developed during the Gigabyte MZ33-AR1 (Turin) porting project. Turin is a server-class AMD platform using a different SoC, but the openSIL integration patterns - particularly around how coreboot initializes the hardware before and after openSIL still carry on.

This makes the work less glamorous than it might appear from the commit log, but it ensures that improvements made for MSI PRO B850-P benefit the Turin platform too, and vice versa.

The first major breakthrough came in the MPIO IP block. As described in Part 2, the platform was hanging during PCIe initialization inside openSIL. Tracing the hang pointed to the early link training phase, specifically to the chipset link authentication step.

In Phoenix openSIL, MpioCfgEarlyLinkAuthentication() existed as a placeholder with no implementation. On mobile Phoenix this did not matter because mobile designs do not use an external Promontory chipset. On a desktop AM5 board like the B850-P, however, the Promontory B850 chipset is connected over a PCIe x4 link and must be authenticated before MPIO can proceed.

The implementation added to the 3mdeb openSIL fork performs the following steps:

  1. Assigns temporary bus numbers to the PCIe root ports to allow early enumeration.
  2. Traverses the PCIe topology recursively to find a USB controller (device class 0x0C), which is a reliable indicator that the Promontory chipset is present and accessible.
  3. If the controller is found, sends the BIOS_MPIO_MSG_AUTHENTICATE_CHIPSET MPIO service request to authenticate the chipset.
  4. Cleans up the temporary bus assignments.

In coreboot, early chipset link training support was added to the Phoenix openSIL glue code. After these changes, the platform no longer hangs during PCIe initialization. openSIL TP1 completes successfully and control returns to coreboot.

SMM initialization challenges

Returning from openSIL TP1 was not the end of the troubles. The next major obstacle was that CPU cores were not entering SMM (System Management Mode). SMM is required for several critical firmware services:

  • SMMSTORE - the coreboot mechanism for persistent storage of UEFI variables. Without SMM, the EDK2 payload cannot initialize its variable store.
  • SMM handlers - security-critical firmware services that must run in SMM context.

With SMM broken, every attempt to boot the EDK2 payload ended in failure. The payload could not read or write UEFI variables, which broke not just boot option persistence, but also Secure Boot configuration and virtually everything else that depends on UEFI runtime services.

The root cause turned out to be missing SMU (System Management Unit) initialization. Phoenix openSIL did not include SMU initialization besides the API to send various requests to SMU. The SMU is responsible for power management and core control on AMD platforms. Without proper SMU initialization, the CPU cores likely cannot transition into SMM correctly.

SMU initialization: adding a missing IP block

Adding SMU initialization to Phoenix openSIL was a substantial effort because there was no existing code to start from within the Phoenix PoC branch.Beyond simply adding the SMU initialization routines, there was also an ordering problem. SMU initialization happens in two steps: after CCX initialization done and after PCIe training done checkpoint. In Phoenix openSIL the CCX (CPU Complex) initialization was running before MPIO (PCIe training). This ordering is acceptable in a UEFI environment where the PEI dispatcher can handle dependency graphs through PPI notifications. openSIL running inside coreboot does not have that luxury - the initialization order is determined by the position of entries in the xSIM module and the IP2IP/Xfer table calls in IP blocks. To ensure proper SMU initialization order, the CCX initialization had to be moved to run after MPIO. This is reflected in the IP block list reorganization in the openSIL commit.

After these changes, SMMSTORE started working. The UEFI variable store could be initialized and we were able to configure boot entries - and then actually boot from disk. The coreboot console log showing successful disk boot is available here. This is a significant milestone: it demonstrates that porting NBIO and SMU to the desktop AM5 variant is progressing well, and that the changes we are making have a direct positive impact on platform behavior.

NBIO IP block changes porting

The NBIO (North Bridge I/O) block is responsible for initializing the I/O fabric, including PCIe root complex setup, IOMMU, and related subsystems. Much of the NBIO code for Phoenix desktop is functionally identical to the mobile variant, with differences in register addresses, feature flags, and the presence/absence of certain devices.

The porting work here was largely a process of adding AMD’s Phoenix AM5 register programming to the existing mobile Phoenix code. New parameters were needed for desktop-specific settings, they were added as new configuration knobs to openSIL.

The coreboot-side changes include updating the openSIL IP block parameters from devicetree values, e.g. based on the device enablement:

1
2
3
4
input->Usb4Rt0En            = is_dev_enabled(DEV_PTR(usb4_router_0));
input->Usb4Rt0PcieTnlEn     = is_dev_enabled(DEV_PTR(usb4_pcie_bridge_0));
input->Usb4Rt1En            = is_dev_enabled(DEV_PTR(usb4_router_1));
input->Usb4Rt1PcieTnlEn     = is_dev_enabled(DEV_PTR(usb4_pcie_bridge_1));

This commit wires mainboard-specific settings from the devicetree.cb into the structures that openSIL reads during initialization.

FCH SD controller: silencing a phantom device

During EDK2 payload bring-up, an exception occurred when the payload attempted to initialize the SD card controller. This was surprising because the MSI PRO B850-P does not have an SD card slot, and Phoenix silicon is not supposed to include an SD controller at all.

It turns out the SD controller PCI device is visible in the PCI configuration space even though the hardware is not actually present. The EDK2 PCI driver faithfully tried to bind a driver to it and faulted. The fix was to explicitly disable the SD controller through openSIL so that it is invisible to the payload.

The SD controller IP block implementation adds a new FchSd IP block to Phoenix openSIL. The key function FchInitEnvSd() modifies PMIO registers 0xD3 and 0xE8 to control the SD controller and AOAC (Always-On Always-Connected) power domain to hide the PCI device. For Phoenix the default SD mode is disable, which removes the phantom SD PCI device from the configuration space.

With this in place, the EDK2 payload no longer faults on SD initialization and continues to the setup menu and OS boot.

The corresponding coreboot change describes the device in the chipset devicetree so the mode can be set per-board.

FCH ACPI and Resource Manager fixes

Several smaller but critical fixes were needed in FCH ACPI and the openSIL Resource Manager (RcMgr) to get further.

Without these fixes, two classes of problems occurred:

  • I/O port mismatches. The FCH ACPI block programs base addresses for ACPI timer and PM1 event registers. If these don’t match what coreboot or the payload expects, timer-based operations malfunction. This caused hangs in the EDK2 payload when using HPET timers.

  • Unallocated MMIO space. The Resource Manager is responsible for reserving MMIO windows for all devices. If a device’s BAR falls outside the declared resources, PCI enumeration attempts to access unmapped space and typically hangs or produces spurious errors.

RcMgr fixes ensure the MMIO windows are wide enough to cover all the PCIe endpoints discovered during enumeration. Some PCI enumeration problems remain - particularly for devices behind the Promontory chipset - but those are expected at this stage because Promontory chipset initialization is not yet complete. Its IP block development is reserved for a dedicated milestone:

Task 6. Port Phoenix AM5 specific code to openSIL:

  • Milestone a. Port Promontory I/O expansion chipset support to OpenSIL

    The Phoenix OpenSIL support only mobile Phoenix CPUs. Board designs with desktop CPUs also use Promontory chipset to provide additional I/O expansions on the board. The goal is to add Promontory 21 initialization to Phoenix OpenSIL, by adding new IP block to OpenSIL and necessary Kconfig option to differentiate between mobile and desktop Phoenix CPUs to conditionally include the Promontory 21 IP block initialization.

GFX: partially ported, fundamentally limited

The GFX (Graphics) block in Phoenix openSIL is minimal. Unlike NBIO or CCX, where there is a meaningful body of initialization code to port, the Phoenix openSIL GFX implementation contains only some GPU N6 register tables reporting. It does not perform any integrated graphics initialization or display engine setup.

At this point we do not have any idea for why the GFX block in Phoenix PoC openSIL is so sparse. We have created an issue to track this problem.

The main idea to bring up integrated graphics was to rely on the VGA option ROM (VBIOS). However, this approach hits a hard architectural constraint on Phoenix AM5 desktop platforms: the UMA framebuffer is allocated above 4 GiB. A standard 32-bit VGA option ROM cannot address memory above 4 GiB, so the VBIOS would be unable to initialize the framebuffer at its actual location. Changing this configuration is not possible through the vendor BIOS setup menu. Nor is it possible with coreboot, because the setting is saved in APCB, which is static in coreboot.

Alternative strategies for integrated graphics initialization will need to be explored.

As a result, Milestone 6c (NBIO, SMU, GFX) is partially complete: NBIO and SMU have been ported and are working, but GFX initialization remains unresolved. The graphics story will continue in a dedicated effort. The Milestone 6c is fulfilled in 80% (the GFX block budget was smaller than NBIO and SMU, as it was expected to take much less work to port).

IRQ routing: expected gap

When booting Linux, the kernel logs show complaints about missing IRQ routing information:

1
2
[    4.921680] pci 0000:00:08.1: can't derive routing for PCI INT A
[    4.928556] pci 0000:00:08.1: PCI INT A: not connected

This is expected at this stage of the project. IRQ routing is communicated to the operating system through ACPI _PRT (PCI Routing Table) methods. Adding these tables is the subject of a dedicated milestone:

Task 7. Platform-feature enablement:

  • Milestone a. Phoenix desktop-specific ACPI tables

    Extend coreboot ACPI code for Phoenix to support AM5 socket desktop parts.

This is analogous to what was done for Turin on the MZ33-AR1 board. The IRQ routing tables will be added once the silicon initialization is stable enough to justify the effort.

CXL: a phantom IP block

Phoenix openSIL contains a CXL (Compute Express Link) IP block. CXL is not available on Phoenix SoC - neither on desktop AM5 parts nor on mobile Phoenix. Moreover, the CXL initialization code is never called in Phoenix openSIL. The AMD reference code for Phoenix AM5 also does not include CXL code at all.

Our assessment is that the CXL IP block was mistakenly included in the Phoenix openSIL Proof of Concept. It appears to have been copied from a server platform (where CXL is relevant) without being removed during the adaptation to Phoenix.

The practical consequence is that Milestone 6e (MPIO, CXL) delivers the MPIO porting work but not CXL porting, because there is nothing to port - the CXL block has no functional counterpart on Phoenix AM5.

The budget originally allocated for CXL porting work will be redirected to graphics initialization, which is a more impactful use of the remaining project resources. The Milestone 6e should be considered fulfilled in 80% (the CXL block budget was smaller than MPIO, as it was expected to take much less work to port). Theremaining 20% will be used in the incoming GFX IP block work.

openSIL code quality observations

Working with Phoenix openSIL in this phase reinforced the impression that the code quality is lower than what was seen in Turin or Genoa. The Phoenix PoC was released significantly later than the Turin PoC - over half a year of delay - which might indicate difficulties with porting, testing, or release approvals. Unlike Turin and Genoa, there is also no sample UEFI board reference code for Phoenix, which reduces the available reference material.

A representative example of the code style in the NBIO IP block tables:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#define NBIO_NBIF_ATOMIC_TBL \
        SMN_ENTRY_RMW(NBIFMMx10131014, \
BIT18_MASK_AAAABFP, \
(0x1 << BIT18_OFFSET_AAAABFQ) \
), \
        SMN_ENTRY_RMW(NBIFEPFCFGx1014008C, \
BIT6_MASK_AAAAAYT | \
BIT7_MASK_AAAAAYR, \
(0x1 << BIT6_OFFSET_AAAAAYU) | \
(0x0 << BIT7_OFFSET_AAAAAYS) \
), \

The macros seem auto-generated, indentation is inconsistent, and the symbolic names (BIT18_MASK_AAAABFP, BIT6_OFFSET_AAAAAYU) contain no semantic information about what register field they control. Working with tables like this requires cross-referencing with hardware documentation for each entry to understand what is actually being configured. This is presumably intentional - it limits the amount of register-level detail that would be disclosed by the open-source release - but it makes maintenance and porting significantly more tedious.

Summary

This post covered the third phase of the MSI PRO B850-P coreboot port:

  1. MPIO: Implemented chipset link authentication for the Promontory B850 chipset, unblocking PCIe initialization and allowing openSIL TP1 to complete. The platform now returns from openSIL TP1 back into coreboot.

  2. SMU: Ported SMU initialization, which was entirely absent in Phoenix openSIL. This had a critical side effect: CPU cores can now enter SMM correctly, enabling SMMSTORE and UEFI variable store initialization.

  3. CCX ordering: Moved CCX initialization after MPIO to ensure correct dependency ordering, using IP2IP and Xfer table restructuring.

  4. NBIO: Generalized and ported NBIO parameters for desktop AM5, wiring devicetree settings into openSIL IP block configuration structures.

  5. FCH SD controller: Added and used a new FchSd IP block to disable the phantom SD PCI device that was causing EDK2 initialization exceptions.

  6. FCH ACPI and RcMgr: Fixed I/O port base addresses and MMIO resource allocations to eliminate timer hangs and PCI enumeration problems.

  7. GFX: Assessed as partially complete. Phoenix openSIL contains minimal GFX code, and the VBIOS approach is blocked by the above-4G UMA framebuffer allocation. Alternative strategies are needed.

  8. CXL: Not ported because CXL is not present on Phoenix AM5 silicon. The CXL block in Phoenix openSIL appears to be an erroneous inclusion. The freed budget will be redirected toward graphics initialization.

The clearest evidence of progress is the almost successful OS boot shown in the console log. This was not possible in Part 2. Linux does report missing IRQ routing information, which is expected and will be addressed in Task 7 Milestone a (Phoenix desktop ACPI tables).

Remaining problems with PCI enumeration behind the Promontory chipset are also expected - Promontory initialization has its own dedicated milestone.

The following milestones have been partially completed:

Task 6. Port Phoenix AM5 specific code to openSIL:

  • Milestone c. Cover Phoenix mobile and desktop silicon initialization differences in openSIL (NBIO, SMU, GFX) - 80% (without GFX)
  • Milestone e. Cover Phoenix mobile and desktop silicon initialization differences in openSIL (MPIO, CXL) - 80% (CXL effort budget moved to GFX)

openSIL community meeting

3mdeb would like to host a new openSIL community meeting to address those problems with the community. There will be an announcement coming next week.

For OEMs & ODMs

If you are an OEM or ODM and see the value in AMD openSIL support for your products, our team can help make it a reality. Reach out to us via our contact form or email us at contact<at>3mdeb<dot>com to start the conversation.

Unlock the full potential of your hardware and secure your firmware with the experts at 3mdeb! If you’re looking to boost your product’s performance and protect it from potential security threats, our team is here to help. Schedule a call with us or drop us an email at contact<at>3mdeb<dot>com to start unlocking the hidden benefits of your hardware. And if you want to stay up-to-date on all things firmware security and optimization, be sure to sign up for our newsletter:

Huge kudos to the NLnet Foundation for sponsoring the project.

NLnet


Michał Żygowski
Firmware Engineer with networking background. Feels comfortable with low-level development using C/C++ and assembly. Interested in advanced hardware features, security and coreboot. Core developer of coreboot. Maintainer of Braswell SoC, PC Engines, Protectli and Libretrend platforms.