Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4a50acd
feat(Linker Script): Reorganize + Small improvements to the FLASH.ld
FoniksFox May 2, 2026
da9ba24
feat(Linker Scripts): Add .dtcm_rodata section
FoniksFox May 2, 2026
8ff88b0
feat(Linker Script)!: Apply all use cases + macros
FoniksFox May 3, 2026
a573632
feat(Reset_Handler): Call extern BoardInit() function for early hardw…
FoniksFox May 3, 2026
9e7670b
fix(LinkerScript): Provide needed symbols
FoniksFox May 4, 2026
8cedb99
feat(System): Move System.c to ST-LIB
FoniksFox May 4, 2026
5570659
style(BoardInit): Comments
FoniksFox May 4, 2026
219a5db
feat(ST-LIB): Add constexpr to instance_of()
FoniksFox May 4, 2026
f2ccc86
Merge remote-tracking branch 'origin/development' into feat/Improve-L…
FoniksFox Jun 1, 2026
0ea71f5
fix: Syntax for weak
FoniksFox Jun 1, 2026
2598974
fix(dtcm.rodata): Section name mismatch
FoniksFox Jun 1, 2026
6468ba0
fix(BoardInit): Make BoardInit a weak symbol in a .c
FoniksFox Jun 1, 2026
8863075
chore(EXTI): Remove comment
FoniksFox Jun 1, 2026
ce980f3
feat!: Add inline specifiers to handle COMDAT sections
FoniksFox Jun 1, 2026
31d9ec5
feat: Leave ConfigurationChecker weak for user override
FoniksFox Jun 1, 2026
02c1cc9
chore: Add changeset
FoniksFox Jun 1, 2026
e985c97
fix(tests)
FoniksFox Jun 1, 2026
307ceee
fix: tests
FoniksFox Jun 1, 2026
8373d45
Merge branch 'development' into feat/Improve-Linker-Scripts
FoniksFox Jun 4, 2026
3ba330a
fix(LinkerScript): Fix vairous things that could hardfault
FoniksFox Jun 10, 2026
362664d
Merge remote-tracking branch 'origin/development' into feat/Improve-L…
FoniksFox Aug 4, 2026
c4cc2da
fix(TimerDomain): Merge error
FoniksFox Aug 4, 2026
3e4b51f
fix(LTO): Now it works with flags instead of the builtin from cmake
FoniksFox Aug 4, 2026
27b3955
chore: Update changeset
FoniksFox Aug 4, 2026
b5dc050
chore(Linker Script): Make the linker script more consistent
FoniksFox Aug 4, 2026
3bcb179
fix: Section boot_code not boot
FoniksFox Aug 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .changesets/refactor-linker-script.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
release: major
summary: Refactor linker script, startup code, and memory model with unified copy/zero tables, configurable ITCM, and weak BoardInit. Also fixes LTO.

## Implemented

### Linker Script (`LinkerScript.ld`)
- **Unified copy table**: all initialized data sections (ISR vector, ITCM code, `.data`, `.dtcm_rodata`, D1/D2/D3 NC and cached data/rodata) are copied from FLASH to RAM by a single generic loop in `Reset_Handler`. No more hand-written copy per section.
- **Unified zero table**: all BSS sections (DTCM `.bss`, D1/D2/D3 NC and cached BSS) are zero-initialized by the same generic mechanism.
- **Configurable ITCM**: `__ITCM_SIZE` and `__ITCM_BUILD` macros (passed via C preprocessor `-D` at build time) control ITCM size and whether `.text` is placed in ITCM instead of FLASH.
- **ISR vector always in ITCM**: the interrupt vector table is unconditionally placed in ITCMRAM and copied at startup.
- **DTCM constants**: `.dtcm_rodata` section for constants explicitly placed in DTCM (via `DTCM_RODATA` / `DTCM_RODATA_INLINE` macros), initialized from FLASH by the copy table.
- **Initialized data for all memory domains**: D1, D2, D3 each have non-cached and cached data/rodata sections (`>RAM_Dx AT> FLASH`) copied by the copy table.
- **Null-pointer guard**: 32-byte MPU region at `0x00000000` (NO_ACCESS) catches runtime null dereferences. Vector table relocated to a 1024-byte aligned location after the 32 security bytes, loaded in VTOR via `.null_guard` NOLOAD section. Region 12 > region 11 → takes priority.
- **LMA collision guard**: `BYTE(0)` in every `AT> FLASH` section prevents empty sections from clustering at the same PhysAddr, suppressing STM32_Programmer "overlapping segments" warnings.

### Startup Code (`StartupCode.s`)
- Replaced per-section manual copy with generic copy-table loop (`__copy_table_start` → `__copy_table_end`).
- Replaced per-section manual BSS zeroing with generic zero-table loop (`__zero_table_start` → `__zero_table_end`).
- Removed `Reset_Handler` reliance on hardcoded section symbols; everything is table-driven.
- Calls `weak BoardInit()` between `SystemInit` and global constructors, allowing early hardware initialization from C++.

### System / Board Init (`System.c`)
- Moved from template-project to ST-LIB so all projects benefit.
- Provides `weak BoardInit()` and `weak ConfigurationChecker()` — user overrides in firmware.

### MPU (`MPU.hpp`)
- Fixed `MPUDomain::Instance::as()` and `construct()`: `Request::e` → `Target.e` for valid constexpr member access.
- Fixed `static_assert` logic: `is_nc && volatile` → `!is_nc || volatile` (cached buffers no longer trigger the assert).
- Added null-pointer guard region (region 12, `0x00000000`, 32 bytes, NO_ACCESS).
- Inline specifiers for all `*_INLINE` macros (since inline things are placed in special COMDAT sections that must be separate one from another and everything else).

## Not implemented (left as weak symbols)
- `ConfigurationChecker`: a function to validate ITCM size and other build-time configuration at runtime. User can define it to add custom startup checks.

## Migration guide (template-project)
The corresponding template-project PR adapts `BoardInit` to the new weak function contract, and changes the CMAKE as needed. See the template-project for details.
7 changes: 3 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ add_library(${STLIB_LIBRARY} OBJECT
$<$<AND:$<BOOL:${CMAKE_CROSSCOMPILING}>,$<BOOL:${USE_ETHERNET}>>:${HALAL_C_ETH_PHY}>


$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${CMAKE_CURRENT_LIST_DIR}/System.c>
$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${CPP_UTILITIES_C}>
$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${CPP_UTILITIES_CPP}>

Expand Down Expand Up @@ -480,6 +481,8 @@ target_compile_options(${STLIB_LIBRARY} PRIVATE
$<$<BOOL:${CMAKE_CROSSCOMPILING}>:-fdata-sections>
$<$<BOOL:${CMAKE_CROSSCOMPILING}>:-fno-exceptions>

$<$<AND:$<BOOL:${ENABLE_LTO}>,$<NOT:$<CONFIG:DEBUG>>>:-flto=auto>

-Wno-psabi

$<$<COMPILE_LANGUAGE:C>:-w>
Expand Down Expand Up @@ -530,10 +533,6 @@ target_include_directories(${STLIB_LIBRARY} PUBLIC
${CMAKE_CURRENT_LIST_DIR}/Inc/ST-LIB_HIGH
)

if(ENABLE_LTO)
set_property(TARGET ${STLIB_LIBRARY} PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
set_property(TARGET ${STLIB_LIBRARY} PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON)
endif()

if(STLIB_USE_PCH)
if(COMMAND target_precompile_headers)
Expand Down
278 changes: 208 additions & 70 deletions Inc/HALAL/Models/MPU.hpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Inc/HALAL/Models/SPI/SPI2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1326,7 +1326,7 @@ struct SPIDomain {
}

template <std::size_t N> struct Init {
static inline std::array<Instance, N> instances{};
static inline std::array<Instance, N> instances;

static void init(
std::span<const Config, N> cfgs,
Expand Down
3 changes: 1 addition & 2 deletions Inc/HALAL/Models/TimerDomain/TimerDomain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,6 @@ struct InputCaptureInfo {
uint32_t frequency;
};

static ST_LIB::InputCaptureInfo input_capture_info_dummy;

constexpr std::array<uint8_t, 25> create_timer_idxmap() {
std::array<uint8_t, 25> result{};

Expand Down Expand Up @@ -284,6 +282,7 @@ struct TimerDomain {
/* 2x as big as necessary but this makes indexing easier & faster */
static InputCaptureInfo* input_capture_info[max_instances][input_capture_channels];
static InputCaptureInfo input_capture_info_backing[max_instances][input_capture_channels];
static InputCaptureInfo input_capture_info_dummy;

struct Entry {
std::array<char, 8> name; /* max length = 7 */
Expand Down
8 changes: 4 additions & 4 deletions Inc/HALAL/Services/ADC/ADC.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@

#include "HALAL/Models/Pin.hpp"
#ifdef SIM_ON
#define STLIB_ADC_DMA_BUFFER_ATTR
#define STLIB_ADC_DMA_BUFFER_ATTR(x) inline
#else
#include "HALAL/Models/MPU.hpp"
#define STLIB_ADC_DMA_BUFFER_ATTR D1_NC
#define STLIB_ADC_DMA_BUFFER_ATTR(x) D2_NC_BSS_INLINE(x)
#endif

using std::array;
Expand Down Expand Up @@ -780,8 +780,8 @@ struct ADCDomain {
"ADC DMA buffer size exceeds max_instances"
);

alignas(32) STLIB_ADC_DMA_BUFFER_ATTR
static inline uint16_t dma_buffer_pool[total_dma_slots > 0 ? total_dma_slots : 1]{};
alignas(32) static uint16_t STLIB_ADC_DMA_BUFFER_ATTR(dma_buffer_pool
) dma_buffer_pool[total_dma_slots > 0 ? total_dma_slots : 1]{};

static constexpr bool is_resolved_config(const Config& cfg) {
return cfg.peripheral != Peripheral::AUTO && cfg.channel != Channel::AUTO;
Expand Down
18 changes: 9 additions & 9 deletions Inc/HALAL/Services/DFSDM/DFSDM.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "HALAL/Models/DMA/DMA2.hpp"
#include "HALAL/Models/MPU.hpp"

#define STLIB_DFSDM_DMA_BUFFER_ATTR D1_NC
#define STLIB_DFSDM_DMA_BUFFER_ATTR(x) D2_NC_BSS_INLINE(x)

#define Oversampling_MAX 1024
#define Oversampling_MAX_Filter_4 215
Expand Down Expand Up @@ -992,14 +992,14 @@ struct DFSDM_CHANNEL_DOMAIN {
sizes.filter0 + sizes.filter1 + sizes.filter2 + sizes.filter3;

// Filter Buffers
alignas(32) STLIB_DFSDM_DMA_BUFFER_ATTR
static inline int32_t Buffer_Filter0[sizes.filter0 > 0 ? sizes.filter0 : 1]{};
alignas(32) STLIB_DFSDM_DMA_BUFFER_ATTR
static inline int32_t Buffer_Filter1[sizes.filter1 > 0 ? sizes.filter1 : 1]{};
alignas(32) STLIB_DFSDM_DMA_BUFFER_ATTR
static inline int32_t Buffer_Filter2[sizes.filter2 > 0 ? sizes.filter2 : 1]{};
alignas(32) STLIB_DFSDM_DMA_BUFFER_ATTR
static inline int32_t Buffer_Filter3[sizes.filter3 > 0 ? sizes.filter3 : 1]{};
alignas(32) STLIB_DFSDM_DMA_BUFFER_ATTR(Buffer_Filter0
) static int32_t Buffer_Filter0[sizes.filter0 > 0 ? sizes.filter0 : 1]{};
alignas(32) STLIB_DFSDM_DMA_BUFFER_ATTR(Buffer_Filter1
) static int32_t Buffer_Filter1[sizes.filter1 > 0 ? sizes.filter1 : 1]{};
alignas(32) STLIB_DFSDM_DMA_BUFFER_ATTR(Buffer_Filter2
) static int32_t Buffer_Filter2[sizes.filter2 > 0 ? sizes.filter2 : 1]{};
alignas(32) STLIB_DFSDM_DMA_BUFFER_ATTR(Buffer_Filter3
) static int32_t Buffer_Filter3[sizes.filter3 > 0 ? sizes.filter3 : 1]{};

static inline std::array<Instance, N> instances{};

Expand Down
1 change: 1 addition & 0 deletions Inc/MockedDrivers/stm32h7xx_hal_mock.h
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,7 @@ enum {
#define MPU_REGION_NUMBER8 (0x08U)
#define MPU_REGION_NUMBER10 (0x0AU)
#define MPU_REGION_NUMBER11 (0x0BU)
#define MPU_REGION_NUMBER12 (0x0CU)

#define MPU_REGION_ENABLE (0x01U)
#define MPU_REGION_SIZE_4GB (0x1FU)
Expand Down
7 changes: 7 additions & 0 deletions Inc/ST-LIB.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,10 @@ template <BoardFaultPolicy FaultPolicyT, auto&... devs> struct Board {
};

} // namespace ST_LIB

/**
* @brief This is a function that gets called early in the startup process,
* before the global constructors and main() are called.
* It is responsible for initializing the hardware and peripherals
*/
extern "C" void BoardInit(void);
Loading
Loading