wolfBoot/hal/mpfs250-m.ld

168 lines
5.9 KiB
Plaintext

/* PolarFire SoC MPFS250 M-Mode Linker Script for wolfBoot
*
* This linker script is for running wolfBoot in Machine Mode (M-mode)
* directly from eNVM, executing from L2 SRAM.
*
* Boot flow:
* 1. CPU starts at eNVM reset vector (0x20220100)
* 2. Startup code in eNVM copies main code to L2_SCRATCH
* 3. Jumps to L2_SCRATCH for execution
*
* The first 0x100 bytes of eNVM are reserved for the boot ROM secure boot
* meta information added by mpfsBootmodeProgrammer.
*
* Memory regions:
* FLASH_ENVM - Embedded NVM (128KB - 0x100 for header)
* L2_SCRATCH - L2 Scratchpad SRAM (256KB) - execution and data
*/
OUTPUT_ARCH( "riscv" )
ENTRY( _reset )
MEMORY
{
/* The first 0x100 bytes of eNVM are used for boot ROM secure boot meta information
* This offset is added by mpfsBootmodeProgrammer (bootmode 1) */
FLASH_ENVM (rx) : ORIGIN = 0x20220100, LENGTH = 128k - 0x100
/* L2 Scratchpad SRAM - 256 KB used (2 of 4 scratchpad ways).
* Attempted 512 KB (all 4 ways) to match HSS layout, but ways 8-9
* are not initialized by the bootmode programmer -- stack/HLS
* placed there hit a trap immediately after DDR init. Reverted
* until we add explicit scratchpad init for ways 8-9.
* Address range: 0x0A000000 - 0x0A03FFFF */
L2_SCRATCH (rwx) : ORIGIN = @WOLFBOOT_ORIGIN@, LENGTH = 256k
}
/* Stack size for the boot hart (E51 in M-mode)
* ECC384 + SHA384 + SPMATHALL + NO_ASM measured peak: ~6KB.
* 32KB provides 5x headroom. */
PROVIDE(STACK_SIZE = 32k);
SECTIONS
{
/*
* Reset vector and early initialization code
* This section MUST be in eNVM (VMA = LMA) since CPU starts here.
* It copies the main code to L2_SCRATCH and jumps there.
*/
.init : ALIGN(0x10)
{
_start_text = .;
KEEP(*(.init))
. = ALIGN(0x10);
} > FLASH_ENVM
/*
* Main code section - runs from L2_SCRATCH, stored in FLASH_ENVM
* The .init code will copy this section to L2_SCRATCH before jumping here.
*/
.text : ALIGN(0x10)
{
_start_text_sram = .;
_start_vector = .;
KEEP(*(.isr_vector))
KEEP(*(.trap_vector))
. = ALIGN(0x10);
*(.text*)
*(.rodata*)
*(.srodata*)
. = ALIGN(8);
_end_text = .;
} > L2_SCRATCH AT > FLASH_ENVM
/* Provide load address for copying from flash */
_stored_text = LOADADDR(.text);
_stored_data = LOADADDR(.data);
/* Initialized data section */
.data : ALIGN(0x10)
{
_start_data = .;
KEEP(*(.ramcode*))
. = ALIGN(4);
*(.data*)
. = ALIGN(4);
/* Global pointer is set to .sdata + 0x800 for efficient access
* to small data using gp-relative addressing (+/- 2KB range) */
_global_pointer = . + 0x800;
*(.sdata*)
. = ALIGN(4);
/* Public key store - must be in a copied section so it's available
* in L2 SRAM after startup copies .data from eNVM */
KEEP(*(.keystore*))
. = ALIGN(8);
_end_data = .;
} > L2_SCRATCH AT > FLASH_ENVM
/* Uninitialized data section (cleared to zero on startup) */
.bss (NOLOAD) : ALIGN(0x10)
{
_start_bss = .;
*(.bss*)
*(.sbss*)
*(COMMON)
. = ALIGN(8);
_end_bss = .;
_end = .;
} > L2_SCRATCH
}
/* Heap starts after BSS (between _end and stack) */
PROVIDE(_start_heap = _end);
/* Stack configuration for multi-hart boot
* Memory layout at end of L2_SCRATCH:
* [code/data/bss/heap] ... [secondary stacks] [main stack]
*
* Stack sizes (defined in config or header):
* STACK_SIZE_PER_HART = 8192 (8KB per hart)
* STACK_SIZE = 32K (32KB for main hart E51)
*
* Total stack area: STACK_SIZE + 4 * STACK_SIZE_PER_HART
*/
/* Per-hart stacks for the secondary (U54) park/wake path. The value is
* substituted from the single Makefile STACK_SIZE_PER_HART variable (set in
* the target .config), which ALSO drives the startup asm's -DSTACK_SIZE_PER_HART
* -- so the wake asm (which computes sp with the C macro) and this symbol
* (which places the region) can never disagree. A historical macro-vs-linker
* mismatch placed the woken harts' stacks INSIDE the E51 stack region,
* smashing the monitor when SBI HSM started the secondary harts. */
PROVIDE(STACK_SIZE_PER_HART = @STACK_SIZE_PER_HART@);
/* End of L2 scratchpad */
PROVIDE(_l2_scratch_end = ORIGIN(L2_SCRATCH) + LENGTH(L2_SCRATCH));
/* Main hart (E51) stack at very end, grows downward */
PROVIDE(_end_stack = _l2_scratch_end);
PROVIDE(_main_hart_stack_top = _end_stack);
PROVIDE(_main_hart_stack_bottom = _main_hart_stack_top - STACK_SIZE);
/* Main hart HLS location (at top of main stack minus 64 bytes) */
PROVIDE(_main_hart_hls = _main_hart_stack_top - 64);
/* Secondary hart stacks below main hart stack
* Hart 1 stack: _main_hart_stack_bottom - STACK_SIZE_PER_HART * 0 to - STACK_SIZE_PER_HART * 1
* Hart 2 stack: _main_hart_stack_bottom - STACK_SIZE_PER_HART * 1 to - STACK_SIZE_PER_HART * 2
* etc.
*/
PROVIDE(_secondary_hart_stack_base = _main_hart_stack_bottom - 4 * STACK_SIZE_PER_HART);
/* Provide symbols for M-mode startup code */
PROVIDE(__global_pointer$ = _global_pointer);
/* Size of text section to copy (for startup code) */
PROVIDE(_text_size = _end_text - _start_text_sram);
/* Build-time safety: ensure wolfBoot binary does not overlap image load area.
* Image header is loaded at (WOLFBOOT_LOAD_ADDRESS - IMAGE_HEADER_SIZE). */
ASSERT(_end <= @WOLFBOOT_LOAD_ADDRESS@ - @IMAGE_HEADER_SIZE@,
"ERROR: wolfBoot binary overlaps image load area! Increase WOLFBOOT_LOAD_ADDRESS")
/* Build-time safety: keep at least 4 KB between the end of code/data/bss
* (_end) and the main hart stack bottom so code growth cannot silently
* reach the stack region at the top of L2 Scratch. */
ASSERT(_end <= _main_hart_stack_bottom - 0x1000,
"ERROR: wolfBoot L2 image too close to stack (need 4 KB headroom)")