mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-05-24 08:24:11 +02:00
260 lines
8.2 KiB
Plaintext
260 lines
8.2 KiB
Plaintext
/*
|
||
* SPDX-License-Identifier: MIT OR Apache-2.0
|
||
*
|
||
* Copyright (c) 2021–2024 The rp-rs Developers
|
||
* Copyright (c) 2021 rp-rs organization
|
||
* Copyright (c) 2025 Raspberry Pi Ltd.
|
||
*/
|
||
|
||
MEMORY {
|
||
/*
|
||
* The RP2350 has either external or internal flash.
|
||
*
|
||
* 2 MiB is a safe default here, although a Pico 2 has 4 MiB.
|
||
*/
|
||
FLASH : ORIGIN = 0x10000000, LENGTH = 2048K
|
||
/*
|
||
* RAM consists of 8 banks, SRAM0-SRAM7, with a striped mapping.
|
||
* This is usually good for performance, as it distributes load on
|
||
* those banks evenly.
|
||
*/
|
||
RAM : ORIGIN = 0x20000000, LENGTH = 512K
|
||
/*
|
||
* RAM banks 8 and 9 use a direct mapping. They can be used to have
|
||
* memory areas dedicated for some specific job, improving predictability
|
||
* of access times.
|
||
* Example: Separate stacks for core0 and core1.
|
||
*/
|
||
SRAM4 : ORIGIN = 0x20080000, LENGTH = 4K
|
||
SRAM5 : ORIGIN = 0x20081000, LENGTH = 4K
|
||
}
|
||
|
||
/* # Developer notes
|
||
|
||
- Symbols that start with a double underscore (__) are considered "private"
|
||
|
||
- Symbols that start with a single underscore (_) are considered "semi-public"; they can be
|
||
overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" {
|
||
static mut _heap_size }`).
|
||
|
||
- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a
|
||
symbol is not dropped if it appears in or near the front of the linker arguments and "it's not
|
||
needed" by any of the preceding objects (linker arguments)
|
||
|
||
- `PROVIDE` is used to provide default values that can be overridden by a user linker script
|
||
|
||
- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and*
|
||
the LMA of .data are all `32`-byte aligned. These alignments are assumed by the RAM
|
||
initialization routine. There's also a second benefit: `32`-byte aligned boundaries
|
||
means that you won't see "Address (..) is out of bounds" in the disassembly produced by `objdump`.
|
||
*/
|
||
|
||
PROVIDE(_stext = ORIGIN(FLASH));
|
||
PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM));
|
||
PROVIDE(_max_hart_id = 0);
|
||
PROVIDE(_hart_stack_size = 2K);
|
||
PROVIDE(_heap_size = 0);
|
||
|
||
PROVIDE(InstructionMisaligned = ExceptionHandler);
|
||
PROVIDE(InstructionFault = ExceptionHandler);
|
||
PROVIDE(IllegalInstruction = ExceptionHandler);
|
||
PROVIDE(Breakpoint = ExceptionHandler);
|
||
PROVIDE(LoadMisaligned = ExceptionHandler);
|
||
PROVIDE(LoadFault = ExceptionHandler);
|
||
PROVIDE(StoreMisaligned = ExceptionHandler);
|
||
PROVIDE(StoreFault = ExceptionHandler);
|
||
PROVIDE(UserEnvCall = ExceptionHandler);
|
||
PROVIDE(SupervisorEnvCall = ExceptionHandler);
|
||
PROVIDE(MachineEnvCall = ExceptionHandler);
|
||
PROVIDE(InstructionPageFault = ExceptionHandler);
|
||
PROVIDE(LoadPageFault = ExceptionHandler);
|
||
PROVIDE(StorePageFault = ExceptionHandler);
|
||
|
||
PROVIDE(SupervisorSoft = DefaultHandler);
|
||
PROVIDE(MachineSoft = DefaultHandler);
|
||
PROVIDE(SupervisorTimer = DefaultHandler);
|
||
PROVIDE(MachineTimer = DefaultHandler);
|
||
PROVIDE(SupervisorExternal = DefaultHandler);
|
||
PROVIDE(MachineExternal = DefaultHandler);
|
||
|
||
PROVIDE(DefaultHandler = DefaultInterruptHandler);
|
||
PROVIDE(ExceptionHandler = DefaultExceptionHandler);
|
||
|
||
/* # Pre-initialization function */
|
||
/* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function,
|
||
then the function this points to will be called before the RAM is initialized. */
|
||
PROVIDE(__pre_init = default_pre_init);
|
||
|
||
/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */
|
||
PROVIDE(_setup_interrupts = default_setup_interrupts);
|
||
|
||
/* # Multi-processing hook function
|
||
fn _mp_hook() -> bool;
|
||
|
||
This function is called from all the harts and must return true only for one hart,
|
||
which will perform memory initialization. For other harts it must return false
|
||
and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
|
||
*/
|
||
PROVIDE(_mp_hook = default_mp_hook);
|
||
|
||
/* # Start trap function override
|
||
By default uses the riscv crates default trap handler
|
||
but by providing the `_start_trap` symbol external crates can override.
|
||
*/
|
||
PROVIDE(_start_trap = default_start_trap);
|
||
|
||
SECTIONS
|
||
{
|
||
.text.dummy (NOLOAD) :
|
||
{
|
||
/* This section is intended to make _stext address work */
|
||
. = ABSOLUTE(_stext);
|
||
} > FLASH
|
||
|
||
.text _stext :
|
||
{
|
||
/* Put reset handler first in .text section so it ends up as the entry */
|
||
/* point of the program. */
|
||
KEEP(*(.init));
|
||
KEEP(*(.init.rust));
|
||
. = ALIGN(4);
|
||
__start_block_addr = .;
|
||
KEEP(*(.start_block));
|
||
. = ALIGN(4);
|
||
*(.trap);
|
||
*(.trap.rust);
|
||
*(.text.abort);
|
||
*(.text .text.*);
|
||
. = ALIGN(4);
|
||
} > FLASH
|
||
|
||
/* ### Picotool 'Binary Info' Entries
|
||
*
|
||
* Picotool looks through this block (as we have pointers to it in our
|
||
* header) to find interesting information.
|
||
*/
|
||
.bi_entries : ALIGN(4)
|
||
{
|
||
/* We put this in the header */
|
||
__bi_entries_start = .;
|
||
/* Here are the entries */
|
||
KEEP(*(.bi_entries));
|
||
/* Keep this block a nice round size */
|
||
. = ALIGN(4);
|
||
/* We put this in the header */
|
||
__bi_entries_end = .;
|
||
} > FLASH
|
||
|
||
.rodata : ALIGN(4)
|
||
{
|
||
*(.srodata .srodata.*);
|
||
*(.rodata .rodata.*);
|
||
|
||
/* 4-byte align the end (VMA) of this section.
|
||
This is required by LLD to ensure the LMA of the following .data
|
||
section will have the correct alignment. */
|
||
. = ALIGN(4);
|
||
} > FLASH
|
||
|
||
.data : ALIGN(32)
|
||
{
|
||
_sidata = LOADADDR(.data);
|
||
__sidata = LOADADDR(.data);
|
||
_sdata = .;
|
||
__sdata = .;
|
||
/* Must be called __global_pointer$ for linker relaxations to work. */
|
||
PROVIDE(__global_pointer$ = . + 0x800);
|
||
*(.sdata .sdata.* .sdata2 .sdata2.*);
|
||
*(.data .data.*);
|
||
. = ALIGN(32);
|
||
_edata = .;
|
||
__edata = .;
|
||
} > RAM AT > FLASH
|
||
|
||
.bss (NOLOAD) : ALIGN(32)
|
||
{
|
||
_sbss = .;
|
||
*(.sbss .sbss.* .bss .bss.*);
|
||
. = ALIGN(32);
|
||
_ebss = .;
|
||
} > RAM
|
||
|
||
.end_block : ALIGN(4)
|
||
{
|
||
__end_block_addr = .;
|
||
KEEP(*(.end_block));
|
||
} > FLASH
|
||
|
||
/* fictitious region that represents the memory available for the heap */
|
||
.heap (NOLOAD) :
|
||
{
|
||
_sheap = .;
|
||
. += _heap_size;
|
||
. = ALIGN(4);
|
||
_eheap = .;
|
||
} > RAM
|
||
|
||
/* fictitious region that represents the memory available for the stack */
|
||
.stack (NOLOAD) :
|
||
{
|
||
_estack = .;
|
||
. = ABSOLUTE(_stack_start);
|
||
_sstack = .;
|
||
} > RAM
|
||
|
||
/* fake output .got section */
|
||
/* Dynamic relocations are unsupported. This section is only used to detect
|
||
relocatable code in the input files and raise an error if relocatable code
|
||
is found */
|
||
.got (INFO) :
|
||
{
|
||
KEEP(*(.got .got.*));
|
||
}
|
||
|
||
.eh_frame (INFO) : { KEEP(*(.eh_frame)) }
|
||
.eh_frame_hdr (INFO) : { *(.eh_frame_hdr) }
|
||
}
|
||
|
||
PROVIDE(start_to_end = __end_block_addr - __start_block_addr);
|
||
PROVIDE(end_to_start = __start_block_addr - __end_block_addr);
|
||
|
||
|
||
/* Do not exceed this mark in the error messages above | */
|
||
ASSERT(ORIGIN(FLASH) % 4 == 0, "
|
||
ERROR(riscv-rt): the start of the FLASH must be 4-byte aligned");
|
||
|
||
ASSERT(ORIGIN(RAM) % 32 == 0, "
|
||
ERROR(riscv-rt): the start of the RAM must be 32-byte aligned");
|
||
|
||
ASSERT(_stext % 4 == 0, "
|
||
ERROR(riscv-rt): `_stext` must be 4-byte aligned");
|
||
|
||
ASSERT(_sdata % 32 == 0 && _edata % 32 == 0, "
|
||
BUG(riscv-rt): .data is not 32-byte aligned");
|
||
|
||
ASSERT(_sidata % 32 == 0, "
|
||
BUG(riscv-rt): the LMA of .data is not 32-byte aligned");
|
||
|
||
ASSERT(_sbss % 32 == 0 && _ebss % 32 == 0, "
|
||
BUG(riscv-rt): .bss is not 32-byte aligned");
|
||
|
||
ASSERT(_sheap % 4 == 0, "
|
||
BUG(riscv-rt): start of .heap is not 4-byte aligned");
|
||
|
||
ASSERT(_stext + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), "
|
||
ERROR(riscv-rt): The .text section must be placed inside the FLASH region.
|
||
Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'");
|
||
|
||
ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, "
|
||
ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts.
|
||
Consider changing `_max_hart_id` or `_hart_stack_size`.");
|
||
|
||
ASSERT(SIZEOF(.got) == 0, "
|
||
.got section detected in the input files. Dynamic relocations are not
|
||
supported. If you are linking to C code compiled using the `gcc` crate
|
||
then modify your build script to compile the C code _without_ the
|
||
-fPIC flag. See the documentation of the `gcc::Config.fpic` method for
|
||
details.");
|
||
|
||
/* Do not exceed this mark in the error messages above | */
|