Conversation
board_init_psram() runs from .sram_bootstrap and raises clk_sys before
psram_reinitialize() re-times the QMI for the new clock. Between those two
points the PSRAM window is live but mis-timed, and a PSRAM app is fetching its
instructions through it.
clock_configure() and psram_configure_params() both execute in that window and
both divide 64-bit values, which compiles to a call into libgcc. libgcc was not
listed in .sram_bootstrap, so __aeabi_uldivmod and __udivmoddi4 were placed in
PSRAM and reached through a long-branch veneer:
clock_configure (0x2000597c, SRAM)
bl ____aeabi_uldivmod_veneer (0x20007dc0, SRAM)
ldr pc, [pc] -> 0x1101bfcd (PSRAM)
Auditing the direct callees does not reveal this, because the veneer itself is
SRAM-resident; only following the branch through it does.
Adding libgcc to the section moves both helpers into SRAM. Measured on an
external app using fw2_psram_app(): __aeabi_uldivmod 0x1101bfcc -> 0x20004524,
at a cost of 1,936 bytes of SRAM. hello_psram_exec still passes its layout
check.
This is a latent fault rather than an observed failure: the inherited QMI timing
from the loader stub remains readable at 250 MHz, so the fetch currently
succeeds. It is not guaranteed to across parts or clock changes, which is the
same reasoning that already keeps clocks.c, pll.c, vreg.c and psram.c here.
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.
In short: a PSRAM app spends a brief moment executing code that lives on the
PSRAM chip while that chip's timing settings are being changed. It works today,
but nothing guarantees it will, and the fix is a one-line addition to a list
that already exists for exactly this purpose.
There is no bug to reproduce. No crash, no hang, no visible symptom. This
was found by reading the linked image, not by anything failing. An app built
with
fw2_psram_app()boots and runs correctly with and without this change,which was confirmed on hardware. Treat it as hardening, not a defect report.
Why the moment exists
board_init_psram()runs from SRAM and does, in order:clk_sysclock_configure()psram_configure_params()psram_reinitialize()— re-times the QMI for the new clockBetween step 1 and step 4 the PSRAM timing is set for the old clock. A PSRAM app
is fetching its own instructions from that chip, so any code running in that gap
must live in SRAM instead. That is what
.sram_bootstrapis for, and whyclocks.c,pll.c,vreg.candpsram.care already listed there.What is missing from the list
libgcc. Steps 2 and 3 both divide 64-bit values, which the compiler turns into a
call into libgcc. Those helpers were left in PSRAM, so they are fetched through
the window being reconfigured:
This is easy to miss by reading the code, because the branch target is a veneer
that is itself in SRAM. Only following the branch through the veneer shows that
the real destination is in PSRAM.
The change
One entry added to the
.sram_bootstrapsection list.Effect
Measured on an external app built with
fw2_psram_app():__aeabi_uldivmod0x1101bfcc(PSRAM)0x20004524(SRAM)__udivmoddi40x1101bffc(PSRAM)0x20004554(SRAM)Cost is 1,936 bytes of SRAM. That app boots and runs unchanged with the entry in
place: bootstrap and constructors complete, the audio codec input path comes up,
and capture holds its normal block rate.
hello_psram_execstill passes its layout check, andtests/plustools/tests/pass (87 tests).Why it is worth taking anyway
The current behaviour depends on the QMI timing inherited from the loader stub
staying readable at 250 MHz. That happens to hold, but it is not something the
section list relies on anywhere else — every other entry is there precisely so
that no assumption about the stale window is needed. This makes libgcc
consistent with them.