Numworks-zeta-os/src/linker.ld
2024-04-21 14:08:27 +02:00

166 lines
5.5 KiB
Plaintext

/* This is the linker file it required to map out the memory.
* This linker is heavely inspired by epsilon/omega/upsilon and their bootloader_common.ld.
* It is necessary if we want our os to be considered as valid.
* At this time we can only compile this os to slot B, but it might change in the future */
/* numworks stuff */
STACK_SIZE = 32K;
FIRST_FLASH_SECTOR_SIZE = 4K;
SIGNED_PAYLOAD_LENGTH = 8;
USERLAND_OFFSET = 64K;
/* Set minimum size for stack and dynamic memory. */
/* (The linker will generate an error if there is
* less than this much RAM leftover.) */
/* (1KB) */
_Min_Leftover_RAM = 0x400;
MEMORY
{
FLASH ( rx ) : ORIGIN = 0x90400000, LENGTH = 4M /* This is for the B slot */
RAM ( rxw ) : ORIGIN = 0x20000000, LENGTH = 256K
}
SECTIONS
{
/* epsilon stuff */
.signed_payload_prefix ORIGIN(FLASH) : {
FILL(0xFF);
BYTE(0xFF)
. = ORIGIN(FLASH) + SIGNED_PAYLOAD_LENGTH;
} >FLASH
/* Contains some info and is requiered to be considered as a valid slot by the bootloader.
* Located in info_headers.cpp */
.kernel_header : {
KEEP(*(.kernel_header))
} >FLASH
/* Nothing in there for now */
.slot_info : {
*(.slot_info*)
} >RAM
/* The vector table (handle all the interrupts) located in vector_table.cpp */
.isr_vector_table ORIGIN(RAM) + 512 : AT(ORIGIN(FLASH) + SIZEOF(.signed_payload_prefix) + SIZEOF(.kernel_header)) {
/* When booting, the STM32F412 fetches the content of address 0x0, and
* extracts from it various key infos: the initial value of the PC register
* (program counter), the initial value of the stack pointer, and various
* entry points to interrupt service routines. This data is called the ISR
* vector table.
*
* Note that address 0x0 is always an alias. It points to the beginning of
* Flash, SRAM, or integrated bootloader depending on the boot mode chosen.
* (This mode is chosen by setting the BOOTn pins on the chip).
*
* We're generating the ISR vector table in code because it's very
* convenient: using function pointers, we can easily point to the service
* routine for each interrupt. */
_isr_vector_table_start_flash = LOADADDR(.isr_vector_table);
_isr_vector_table_start_ram = .;
KEEP(*(.isr_vector_table))
_isr_vector_table_end_ram = .;
} >RAM
/* this is to prevent the bootloader from booting straight up in our os (we set all to 0) */
.exam_mode_buffer ORIGIN(FLASH) + SIZEOF(.signed_payload_prefix) + SIZEOF(.kernel_header) + SIZEOF(.isr_vector_table) : {
. = ALIGN(4K);
_exam_mode_buffer_start = .;
KEEP(*(.exam_mode_buffer))
/* Note: We don't increment "." here, we set it. */
. = . + FIRST_FLASH_SECTOR_SIZE;
_exam_mode_buffer_end = .;
} >FLASH
/* Contains some more info and is requiered to be considered as a valid slot by the bootloader.
* Located in info_headers.cpp */
.userland_header : {
. = ORIGIN(FLASH) + USERLAND_OFFSET;
KEEP(*(.userland_header));
} > FLASH
.text : {
. = ALIGN(4);
*(.text)
*(.text.*)
} >FLASH
/* The 'rodata' section contains read-only data,
* constants, strings, information that won't change. */
.rodata : {
*(.rodata)
*(.rodata.*)
} >FLASH
/* TODO, understand what is it's purpose */
.init_array : {
. = ALIGN(4);
_init_array_start = .;
KEEP (*(.init_array*))
_init_array_end = .;
} >FLASH
/* The 'data' section is space set aside in RAM for
* things like variables, which can change. */
.data : {
/* The data section is written to Flash but linked as if it were in RAM.
*
* This is required because its initial value matters (so it has to be in
* persistant memory in the first place), but it is a R/W area of memory
* so it will have to live in RAM upon execution (in linker lingo, that
* translates to the data section having a LMA in Flash and a VMA in RAM).
*
* This means we'll have to copy it from Flash to RAM on initialization.
* To do this, we'll need to know the source location of the data section
* (in Flash), the target location (in RAM), and the size of the section.
* That's why we're defining three symbols that we'll use in the initial-
* -ization routine. */
. = ALIGN(4);
_data_section_start_flash = LOADADDR(.data);
_data_section_start_ram = .;
*(.data)
*(.data.*)
_data_section_end_ram = .;
} >RAM AT> FLASH
/* The 'bss' section is similar to the 'data' section,
* but its space is initialized to all 0s at the
* start of the program. */
.bss : {
/* The bss section contains data for all uninitialized variables
* So like the .data section, it will go in RAM, but unlike the data section
* we don't care at all about an initial value.
*
* Before execution, crt0 will erase that section of memory though, so we'll
* need pointers to the beginning and end of this section. */
. = ALIGN(4);
_bss_section_start_ram = .;
*(.bss)
*(.bss.*)
/* The compiler may choose to allocate uninitialized global variables as
* COMMON blocks. This can be disabled with -fno-common if needed. */
*(COMMON)
_bss_section_end_ram = .;
} >RAM
.heap : {
_heap_start = .;
/* Note: We don't increment "." here, we set it. */
. = (ORIGIN(RAM) + LENGTH(RAM) - STACK_SIZE);
_heap_end = .;
} >RAM
.stack : {
. = ALIGN(8);
_stack_end = .;
. += (STACK_SIZE - 8);
. = ALIGN(8);
_stack_start = .;
} >RAM
/DISCARD/ : {
/* exidx and extab are needed for unwinding, which we don't use */
*(.ARM.exidx*)
*(.ARM.extab*)
}
}