RISC-V OpenSBI Ports: Map Device-Tree Hart IDs to Dense Runtime Indices

An OpenSBI platform port works with CPU nodes numbered 0 and 1 but misroutes per-hart data after moving to a system whose hart IDs are 0 and 4. Replacing one array bound may avoid a crash while leaving the interrupt context attached to the wrong hart.

The migration involves three identities: architectural hart ID, dense runtime hart index and interrupt-controller context index. Follow how the pinned implementation derives each one.

Build the map from the device tree actually consumed

The Machine-Level ISA permits noncontiguous hart IDs. Uniqueness does not imply that an ID is an array position.

In OpenSBI v1.9 generic platform initialization, the firmware walks the device tree's CPU subnodes, parses each hart ID, skips disabled nodes and appends accepted IDs to generic_hart_index2id. The dense count increases as entries are accepted; it is not the largest hart ID plus one.

Consequently, a changed CPU-node order or enabled-node set can change the dense index assigned to an architectural hart. Do not persist a logical index across a firmware or device-tree change and assume it still identifies the same hardware thread.

The tagged FDT helper obtains the ID from the CPU node's reg property. In this implementation the result is a u32, and the helper advances to the second cell when the property contains more than one cell. Audit that actual parser when porting; the architectural width of mhartid alone does not prove arbitrary-width support throughout this firmware path.

Convert at the scratch-data boundary

The v1.9 scratch implementation initializes an index-to-ID table from the platform map. Its reverse lookup searches that table and returns -1U when the ID is absent.

For a hypothetical accepted order [0, 4], hart ID 4 maps to dense index 1. An array sized for two harts should be addressed through that index. But passing index 1 to an interface that expects hart ID 4 is equally wrong: both integers fit in a register, yet they identify different things.

Keep conversion functions visible at API boundaries and handle an unsuccessful lookup before indexing. Naming a variable cpu conceals the distinction; use names that identify which domain the value belongs to.

Diagram mapping a hypothetical sparse CPU set from device-tree hart IDs into dense runtime indices and separately derived PLIC contexts.
Original OpenSBI identity-map diagram. The two-hart example is hypothetical and no firmware was booted.

PLIC context numbers come from another ordering

The OpenSBI v1.9 FDT PLIC driver reads interrupts-extended. For each pair, it follows the CPU interrupt-controller phandle to its CPU node, parses the hart ID, converts it to a dense index and records the pair's ordinal as the corresponding M-mode or S-mode context.

Thus the PLIC context is not the dense hart index, nor a universally fixed multiple of the hart ID. A correct scratch map can coexist with a wrong controller map if a port substitutes one numbering domain for another.

The driver initializes context slots to an absent value and skips unresolved or unknown mappings. A missing usable context should lead to checking the phandle, parent CPU, parsed ID and accepted CPU map, rather than inventing a context number from arithmetic.

Validate the composed map during migration

A proposed offline audit emits one row per accepted CPU: source node, reg hart ID, dense index, scratch association and available interrupt contexts. Compare that map with the intended hardware wiring and the exact device tree supplied to firmware.

Include a sparse-ID case and a disabled CPU node in controlled fixtures. Check both forward and reverse conversion, plus controller association. The target outcome is consistent identity across all three domains, not merely an array that is large enough. No device tree was booted or per-hart state modified here.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *