Feat/improve linker scripts - #640
Conversation
…are initialization
ST-LIB Release Plan
Pending changes
|
There was a problem hiding this comment.
Pull request overview
Refactors the STM32H723 startup/linker infrastructure in ST-LIB to support a table-driven startup initialization (copy/zero tables), configurable ITCM usage, and updated MPU/sectioning conventions to better support multi-memory-domain placement and initialization.
Changes:
- Introduces a unified
LinkerScript.ldwith copy/zero tables, ITCM configuration macros, and expanded D1/D2/D3 cached/non-cached section layout. - Updates
StartupCode.sto use the copy/zero tables and call a weakBoardInit()hook during early startup. - Updates MPU section macros and several drivers to use the new per-domain/per-type linker sections.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| System.c | Adds system initialization implementation plus weak ConfigurationChecker() / BoardInit() hooks for early boot. |
| StartupCode.s | Switches Reset_Handler to table-driven copy/zero init and adds BoardInit call + VTOR relocation logic. |
| LinkerScript.ld | New unified linker script supporting ITCM configuration and copy/zero tables across all memory domains. |
| Src/HALAL/Services/EXTI/EXTI.cpp | Removes a file header comment block (no functional change). |
| Src/HALAL/Models/TimerDomain/TimerDomain.cpp | Adds the new input_capture_info_dummy definition as a proper static member. |
| Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | Moves input_capture_info_dummy from a header-global to a TimerDomain static member declaration. |
| Src/HALAL/Models/MPUManager/MPUManager.cpp | Updates legacy MPUManager pool section name to match the new linker script. |
| Inc/HALAL/Models/MPU.hpp | Overhauls MPU placement macros, updates linker symbol names, fixes as()/construct() constexpr access, adds null-pointer guard region. |
| Inc/HALAL/Services/ADC/ADC.hpp | Moves ADC DMA buffer placement to the new D2 non-cached BSS inline section pattern. |
| Inc/HALAL/Services/DFSDM/DFSDM.hpp | Moves DFSDM DMA buffers to the new D2 non-cached BSS inline section pattern. |
| Inc/HALAL/Models/SPI/SPI2.hpp | Adjusts static inline array definition form for instances. |
| Inc/ST-LIB.hpp | Declares extern "C" void BoardInit(void); for user override from C++ firmware. |
| Inc/MockedDrivers/stm32h7xx_hal_mock.h | Adds MPU_REGION_NUMBER12 needed for the new null-guard MPU region. |
| CMakeLists.txt | Ensures System.c is built for cross-compiling targets; adjusts LTO enabling via compile flags. |
| .changesets/refactor-linker-script.md | Adds a major-release changeset documenting the startup/linker/MPU refactor and migration notes. |
Suppressed comments (1)
StartupCode.s:24
- VTOR is updated to the ITCM vector table before the copy-table runs. If any exception occurs during
ConfigurationChecker,SystemInit, or the copy loop (e.g., HardFault), the CPU will fetch vectors from ITCM before they have been copied, which can make faults un-debuggable or cascade. Consider delaying the VTOR update until after the copy-table has copied.isr_vectorinto ITCM (first copy-table entry), e.g., keep VTOR at the default/Flash vector during early boot and set it right after.L_done_copy_table:.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -0,0 +1,191 @@ | |||
| #define BOOT_ATTR __attribute__((section(".boot"))) __used | |||
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.
Suppressed comments (8)
System.c:1
- BOOT_ATTR places SystemInit/SystemCoreClockUpdate/ConfigurationChecker into an input section named ".boot", but the linker script only keeps ".boot_code*" inside the FLASH-only boot output section. This can make SystemInit land in an orphan section (potentially in ITCM when __ITCM_BUILD is enabled), which is unsafe because Reset_Handler calls SystemInit before the copy-table has initialized RAM/ITCM.
#define BOOT_ATTR __attribute__((section(".boot"))) __used
StartupCode.s:24
- Reset_Handler sets VTOR to the ITCM vector table before the copy-table loop has copied .isr_vector from FLASH into ITCM. If any exception occurs during ConfigurationChecker/SystemInit or during the copy loop (e.g., HardFault), the CPU will fetch vectors from partially-copied/uninitialized ITCM, which can make debugging and recovery unreliable. Consider keeping VTOR pointing at the FLASH vector table initially, and only switching VTOR after the vector table copy entry has completed.
LinkerScript.ld:339 - Same copy-table word-copy alignment issue here: BYTE(0) is added, but __eram_d1_data/__d1_end are captured without re-aligning to 4 bytes. Since Reset_Handler copies 4 bytes at a time, this can overrun into subsequent memory. Align to 4 bytes before capturing these end symbols.
. = ALIGN(32);
__sram_d1_data = ABSOLUTE(.);
*(.ram_d1.user.data)
*(.ram_d1.user.data*)
*(.ram_d1.user.rodata)
*(.ram_d1.user.rodata*)
BYTE(0);
LinkerScript.ld:375
- Same copy-table word-copy alignment issue here: BYTE(0) is added, but __eram_d2_nc_data is captured without re-aligning to 4 bytes. Since Reset_Handler copies 4 bytes at a time, this can overrun into padding/next region. Align to 4 bytes before capturing the end symbol.
{
. = ALIGN(32);
__sram_d2_nc_data = ABSOLUTE(.);
*(.ram_d2_nc.user.data)
*(.ram_d2_nc.user.data*)
*(.ram_d2_nc.user.rodata)
*(.ram_d2_nc.user.rodata*)
LinkerScript.ld:420
- Same copy-table word-copy alignment issue here: BYTE(0) is added, but __eram_d2_data/__d2_end are captured without re-aligning to 4 bytes. Since Reset_Handler copies 4 bytes at a time, this can overrun into subsequent memory. Align to 4 bytes before capturing these end symbols.
} >RAM_D2
.ram_d2_data_rodata :
{
. = ALIGN(32);
__sram_d2_data = ABSOLUTE(.);
*(.ram_d2.user.data)
*(.ram_d2.user.data*)
*(.ram_d2.user.rodata)
LinkerScript.ld:453
- Same copy-table word-copy alignment issue here: BYTE(0) is added, but __eram_d3_nc_data is captured without re-aligning to 4 bytes. Since Reset_Handler copies 4 bytes at a time, this can overrun into padding/next region. Align to 4 bytes before capturing the end symbol.
*(.ram_d3_nc.user.bss)
*(.ram_d3_nc.user.bss*)
__eram_d3_nc_bss = ABSOLUTE(.);
} >RAM_D3
.ram_d3_nc_data_rodata :
{
. = ALIGN(32);
__sram_d3_nc_data = ABSOLUTE(.);
LinkerScript.ld:498
- Same copy-table word-copy alignment issue here: BYTE(0) is added, but __eram_d3_data/__d3_end are captured without re-aligning to 4 bytes. Since Reset_Handler copies 4 bytes at a time, this can overrun into subsequent memory. Align to 4 bytes before capturing these end symbols.
. = ALIGN(32);
*(.ram_d3.user.bss)
*(.ram_d3.user.bss*)
__eram_d3_bss = ABSOLUTE(.);
} >RAM_D3
.ram_d3_data_rodata :
{
. = ALIGN(32);
LinkerScript.ld:483
- This section list includes a duplicated input-section pattern: *(.ram_d3.user.bss) is already included above, and is repeated again after *(.ram_d3.buffer). The second occurrence is redundant and makes it harder to see what is intended to be placed in the D3 cached region.
PROVIDE(_ram_d3_nc_end = __d3_nc_end);
/* MPU D3 Cached Section */
.ram_d3_bss (NOLOAD) :
{
. = ALIGN(32);
__d3_start = ABSOLUTE(.);
__sram_d3_bss = ABSOLUTE(.);
| *(.ram_d1_nc.user.rodata) | ||
| *(.ram_d1_nc.user.rodata*) | ||
| BYTE(0); | ||
|
|
||
| __eram_d1_nc_data = ABSOLUTE(.); |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.
Suppressed comments (11)
System.c:1
- BOOT_ATTR expands to an undefined token
__used, which will fail to compile. Also, the section name.bootis not explicitly collected by LinkerScript.ld (it collects.boot_code*), so these functions can become orphan sections with unpredictable placement when--gc-sectionsis enabled.
#define BOOT_ATTR __attribute__((section(".boot"))) __used
StartupCode.s:25
- VTOR is set to
__sisr_vectorbefore the copy-table runs, so any early exception (HardFault/NMI, etc.) will vector through an uninitialized table in ITCM. VTOR should remain pointing at the Flash vector table until after.isr_vectorhas been copied.
This issue also appears on line 47 of the same file.
StartupCode.s:48
- After the copy-table finishes, VTOR should be switched to the relocated vector table address in ITCM now that the copy has completed.
StartupCode.s:27 - Calling
ConfigurationCheckerbefore the copy/zero tables run makes user overrides unsafe when__ITCM_BUILD=1(the override will likely live in.text/ITCM and hasn’t been copied yet). Call it after memory initialization instead.
This issue also appears on line 65 of the same file.
StartupCode.s:67
ConfigurationCheckershould run after the copy/zero tables so it can safely access initialized data (and so user overrides work when.textis relocated).
LinkerScript.ld:292- This output section appends
BYTE(0);but does not realign the location counter before exporting__eram_d1_nc_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
*(.ram_d1_nc.user.rodata)
*(.ram_d1_nc.user.rodata*)
BYTE(0);
__eram_d1_nc_data = ABSOLUTE(.);
LinkerScript.ld:341
- This output section appends
BYTE(0);but does not realign the location counter before exporting__eram_d1_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
*(.ram_d1.user.rodata)
*(.ram_d1.user.rodata*)
BYTE(0);
__eram_d1_data = ABSOLUTE(.);
LinkerScript.ld:378
- This output section appends
BYTE(0);but does not realign the location counter before exporting__eram_d2_nc_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
*(.ram_d2_nc.user.rodata)
*(.ram_d2_nc.user.rodata*)
BYTE(0);
__eram_d2_nc_data = ABSOLUTE(.);
LinkerScript.ld:424
- This output section appends
BYTE(0);but does not realign the location counter before exporting__eram_d2_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
*(.ram_d2.user.rodata)
*(.ram_d2.user.rodata*)
BYTE(0);
__eram_d2_data = ABSOLUTE(.);
LinkerScript.ld:461
- This output section appends
BYTE(0);but does not realign the location counter before exporting__eram_d3_nc_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
*(.ram_d3_nc.user.rodata)
*(.ram_d3_nc.user.rodata*)
BYTE(0);
__eram_d3_nc_data = ABSOLUTE(.);
LinkerScript.ld:507
- This output section appends
BYTE(0);but does not realign the location counter before exporting__eram_d3_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
*(.ram_d3.user.rodata)
*(.ram_d3.user.rodata*)
BYTE(0);
__eram_d3_data = ABSOLUTE(.);
Closes #625
Closes #653
Closes #658
A refactor of the Linker Script, Startup Code and System.c
Check the corresponding pr in the template-project to see the changes needed to make it work.
It implementes:
Not implemented left as a weak definition so that users can implement their own version):