Foundry/tt/fw/ft_tensix_firmware.ld

83 lines
3.1 KiB
Plaintext

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/*
* ft_tensix_firmware.ld — layout of a Tensix FIRMWARE image (one per processor).
*
* tools/emit_tensix_linker_script.py prepends this processor's constants (FT_FIRMWARE_BASE,
* FT_LOCAL_BASE, ...) from ft_tt_memmap.h; this file only arranges them.
*
* .text in L1 at the processor's firmware slot, `.start` (the reset entry) first.
* .data in the processor's local data memory (Baby RISC-V local RAM,
* .bss tt-isa-documentation BlackholeA0/TensixTile/BabyRISCV/README.md), read-only data
* included so constant tables are fetched from local RAM. The host stages this
* segment in L1 and the firmware copies it in (ft_tt_launch.c).
*
* Exported to the kernel link (which reads them through --just-symbols):
* __fw_export_text_end first 16-byte-aligned L1 address after the firmware text, where a
* kernel's text goes unless it is relocated;
* __fw_export_ldm_end first 16-byte-aligned local address after the firmware's data;
* __stack_top top of local memory; __global_pointer$ 0x7F0 above its base, so
* gp-relative addressing reaches the whole of a TRISC's 4 KiB.
*
* `.segments` (non-loaded) records, for the host loader's size check (ft_tt_elf.c): text
* address twice and its limit (the firmware slot), data address twice and its limit (local
* memory less the processor's minimum stack, less where the data starts).
*
* Status: clean-room replacement of the staged tree's linker script, plan Phase 3.
* Issues: None
* Todo: None
*/
OUTPUT_ARCH("riscv")
ENTRY(_start)
SECTIONS
{
.text FT_FIRMWARE_BASE :
{
KEEP(*(.start))
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
. = ALIGN(4);
}
__fw_export_text_end = ALIGN(16);
.data FT_LOCAL_BASE :
{
__ldm_data_start = .;
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.srodata .srodata.*)
*(.data .data.* .gnu.linkonce.d.*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
. = ALIGN(4);
__ldm_data_end = .;
}
.bss :
{
__ldm_bss_start = .;
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
__ldm_bss_end = .;
}
__fw_export_ldm_end = ALIGN(16);
__stack_top = FT_LOCAL_BASE + FT_LOCAL_SIZE;
__global_pointer$ = FT_LOCAL_BASE + 0x7F0;
__instrn_buffer = 0xFFE40000; /* INSTRN_BUF_BASE, BabyRISCV/PushTensixInstruction.md */
.segments 0 (INFO) :
{
LONG(ADDR(.text)) LONG(ADDR(.text)) LONG(FT_FIRMWARE_SIZE)
LONG(ADDR(.data)) LONG(ADDR(.data))
LONG(FT_LOCAL_SIZE - FT_STACK_MIN_SIZE - (ADDR(.data) - FT_LOCAL_BASE))
}
ASSERT(__fw_export_text_end <= FT_FIRMWARE_BASE + FT_FIRMWARE_SIZE,
"firmware text overflows its L1 slot")
ASSERT(__fw_export_ldm_end <= __stack_top - FT_STACK_MIN_SIZE,
"firmware data leaves less than the minimum stack")
}