Added the boot-at-EL1 option to the S32Z280 entry path - #690
Merged
fdesbiens merged 1 commit intoSep 2, 2026
Conversation
The Armv8-R AEM FVP entry path has carried TX_R52_BOOT_AT_EL1 since it was written, for the case its own comment describes: "an earlier boot stage or a vendor EL2 monitor has already dropped privilege to EL1". This board's entry path did not, so a kernel could not be built as a guest on it at all -- and it is the board where that matters most, because it is the one with silicon behind it. The bracket is the whole change. Everything from the Thumb reset trampoline to the ERET goes inside #ifndef TX_R52_BOOT_AT_EL1, and the #else supplies a one-instruction A32 _start that branches to el1_entry. A32 AND NOT T32, which is the one real difference from the standalone entry. The core resets in Thumb state here because the RTU boot instruction NXP plants is a T32 branch, but a guest is not reached by reset: it is reached by the monitor's ERET, and the monitor chooses the state through SPSR.T. Get the two out of agreement and the guest dies on its first instruction with an undefined-instruction exception, which looks exactly like a bad entry address and sends the reader to the loader instead of to the ERET. WHAT THE MONITOR INHERITS is enumerated at the #ifndef, next to the code it replaces rather than in a document, because that is where somebody adding a third board will be looking. This board's EL2 block is considerably larger than the model's, and each item on the list is something a guest at EL1 provably cannot do rather than something it merely does not: CNTFRQ is writable only at the highest implemented exception level and reads zero out of reset; HCPTR.TCP10/TCP11 reset set, trapping every EL1 floating-point access; HSCTLR.TE is an EL2 register (SCTLR.TE is EL1's, and el1_entry still clears it below); ICC_HSRE.SRE makes every other ICC_* and ICH_* register exist at all; the low-latency peripheral port enables reset to zero and an EL1 write to that register traps to EL2; and the TCM enables are per-core with ENABLEEL2 SILENTLY IGNORED from EL1 -- measured on both BTCM and CTCM, the base took and bit 0 took while bit 1 stayed clear. CNTHCTL.PL1PCTEN and PL1PCEN are the deliberate omission from that list, and the note says why. This path opens both, because a standalone kernel owns the physical timer. A monitor that TIME-partitions its guests must not: a partition's physical time keeps running while it is descheduled, so a guest reading it can observe that it was not running. That is the monitor's decision rather than this file's, which is why the list says what a guest cannot do rather than what a monitor should. Verified both ways. The three standalone images build and link unchanged, and a kernel built with the option boots at EL1 on a S32Z280-594EVB under an EL2 monitor, runs two threads through a queue and a semaphore, and reports back -- with no other change to the kernel or to its port. Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
The Armv8-R AEM FVP entry path has carried
TX_R52_BOOT_AT_EL1since it was written, for the case its own comment describes: "an earlier boot stage or a vendor EL2 monitor has already dropped privilege to EL1". The S32Z280 entry path did not, so a kernel could not be built as a guest on that board at all -- and it is the board where that matters most, because it is the one with silicon behind it.The bracket is the whole change. Everything from the Thumb reset trampoline to the
ERETgoes inside#ifndef TX_R52_BOOT_AT_EL1, and the#elsesupplies a one-instruction A32_startthat branches toel1_entry.One file, additive, and no standalone build changes behaviour: with the option undefined the preprocessor produces the same code it produced before. Checked rather than asserted -- the assembled object has the same sections at the same sizes (
.text.bootis 0x66c either way) and disassembles identically.A32 and not T32
This is the one real difference from the standalone entry, and it is worth stating because getting it wrong does not fail where you would look.
The core resets in Thumb state on this board, because the boot instruction the RTU is given is a T32 branch. But a guest is not reached by reset -- it is reached by the monitor's
ERET, and the monitor chooses the execution state throughSPSR.T. If the two disagree, the guest dies on its first instruction with an undefined-instruction exception that looks exactly like a bad entry address, and sends the reader to the loader instead of to theERET.What the monitor inherits
Enumerated at the
#ifndefitself, next to the code it replaces rather than in a document, because that is where somebody adding a third board will be looking. This board's EL2 block is considerably larger than the model's, and each item is something a guest at EL1 provably cannot do rather than something it merely does not:CNTFRQ-- writable only at the highest implemented exception level, and it reads zero out of reset here, so a guest deriving a tick interval from it divides by zero.HCPTR.TCP10/TCP11-- both reset set, trapping every EL1 and EL0 floating-point access to EL2.HSCTLR.TE-- an EL2 register. (SCTLR.TEis EL1's, andel1_entrystill clears that itself.)ICC_HSRE.SRE-- until it is set, every otherICC_*andICH_*system register is UNDEFINED, so an EL1 kernel cannot acknowledge an interrupt at all.IMP_PERIPHPREGIONR-- the low-latency peripheral port enables reset to zero, and an EL1 write to that register traps to EL2 whenHACTLR.PERIPHPREGIONRis clear.IMP_ATCMREGIONR/IMP_BTCMREGIONR-- the TCM enables are per-core andENABLEEL2is silently ignored when written from EL1. Measured on this part, on both BTCM and CTCM: the base took and bit 0 took while bit 1 stayed clear. A guest that places anything in a TCM therefore needs the monitor to program and ECC-preload it, because ECC is enabled here and a TCM location must be written before it can be read.CNTHCTL.PL1PCTENandPL1PCENare the deliberate omission from that list. This path opens both, because a standalone kernel owns the physical timer. A monitor that time-partitions its guests must not: a partition's physical time keeps running while it is descheduled, so a guest reading it can observe that it was not running. Such a monitor hands out the virtual timer and a per-guestCNTVOFFinstead. That is the monitor's decision rather than this file's, which is why the list says what a guest cannot do rather than what a monitor should do.Verification
Both ways.
TX_R52_USE_THREADX_IRQpath -- with no change to the kernel or toports/cortex_r52beyond this one bracket.