Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions klib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# set the sources
set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/entry/entry.c
${CMAKE_CURRENT_SOURCE_DIR}/entry/secondary.cpp
)

set(HEADERS_PRIVATE
Expand Down
80 changes: 80 additions & 0 deletions klib/entry/secondary.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include <stdint.h>

#pragma pack(push, 1)

/**
* @brief Struct for memory segments that are loaded after the startup code is run
*
*/
struct data_memory_segment_t {
const uint32_t *rom_start;
uint32_t *start;
uint32_t *end;
};

/**
* @brief Struct for bss memory segments that are cleared after the startup code is run
*
*/
struct bss_memory_segment_t {
uint32_t *start;
uint32_t *end;
};

#pragma pack(pop)

extern "C" {
// multisection data segment symbol
extern const data_memory_segment_t __multisection_data_start;

// multisection bss segment symbol
extern const bss_memory_segment_t __multisection_bss_start;
}

namespace klib::entry {
void secondary_memory_loader() {
// loop over all data segments
for (const data_memory_segment_t *segment = &__multisection_data_start; ; segment++) {
// check if we have reached the end of the segments
if (!segment->start && !segment->end && !segment->rom_start) {
// invalid segment
break;
}

// get the length of the segment
const uint32_t length = ((segment->end - segment->start) + (sizeof(uint32_t) - 1)) / sizeof(uint32_t);

// check if we have any length to copy
if (!length) {
continue;
}

// copy rom to ram
for (uint32_t i = 0; i < length; i++) {
((volatile uint32_t*)segment->start)[i] = segment->rom_start[i];
}
}

// loop over all bss segments
for (const bss_memory_segment_t *segment = &__multisection_bss_start; ; segment++) {
// check if we have reached the end of the segments
if (!segment->start && !segment->end) {
// invalid segment
break;
}

// get the length of the segment
const uint32_t length = ((segment->end - segment->start) + (sizeof(uint32_t) - 1)) / sizeof(uint32_t);

// check if we have any length to copy
if (!length) {
continue;
}

// clear the bss segment
for (uint32_t i = 0; i < length; i++) {
((volatile uint32_t*)segment->start)[i] = 0x00;
}
}
}
}
16 changes: 16 additions & 0 deletions klib/entry/secondary.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef KLIB_SECONDARY_HPP
#define KLIB_SECONDARY_HPP

#include <cstdint>

namespace klib::entry {
/**
* @brief A secondary memory loader. This loader should be
* called afer the memories are initialized by the user
* code. Constructor(102) is reserved for this function.
*
*/
void secondary_memory_loader();
}

#endif
6 changes: 4 additions & 2 deletions project/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# include the linkerscript generator needed to preprocess the linkerscripts
include (${CMAKE_SOURCE_DIR}/targets/arm/linkerscript/linkerscript.cmake)

# set the sources
set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
Expand Down Expand Up @@ -40,8 +43,7 @@ target_link_libraries(klib_project PUBLIC target_cpu)
target_link_libraries(klib_project PUBLIC m)

# link to the linkerscript of the target cpu
target_link_options(klib_project PUBLIC "-T${TARGET_LINKERSCRIPT}")
set_target_properties(klib_project PROPERTIES LINK_DEPENDS ${TARGET_LINKERSCRIPT})
add_linkerscript(klib_project ${TARGET_LINKERSCRIPT} "")

# add the project directory to the include directories
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
Expand Down
26 changes: 26 additions & 0 deletions targets/arm/linkerscript/linkerscript.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# helper function to preprocess a linker script. This allows
# using C preprocessor in the linkerscript files (including
# macroes, conditionals, etc)
function(add_linkerscript target linkerscript options)
set(output "${CMAKE_BINARY_DIR}/linkerscript.ld")
set(CURRENT_DIR "${CMAKE_SOURCE_DIR}/targets/arm/linkerscript")

# run the preprocessor on the linkerscript
add_custom_command(
OUTPUT ${output}
# run the linkerscript through the C preprocessor. Force include the base linkerscript template.
COMMAND ${CMAKE_C_COMPILER} -E -P -x c ${linkerscript} -o ${output} -include ${CURRENT_DIR}/linkerscript.ld ${options}
DEPENDS ${linkerscript} ${CURRENT_DIR}/linkerscript.ld
COMMENT "Preprocessing linker script ${linkerscript}"
VERBATIM
)

# create a custom target to generate the linkerscript
add_custom_target(generate_linkerscript DEPENDS "${output}")
add_dependencies(${target} generate_linkerscript)

# add the linkerscript to the target
target_link_options(${target} PUBLIC "-T${output}")
set_target_properties(${target} PROPERTIES LINK_DEPENDS ${output})
endfunction()

141 changes: 141 additions & 0 deletions targets/arm/linkerscript/linkerscript.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/* helpers to combine strings with a parameter */
#define COMBINE_STRX(a,b) a##b
#define COMBINE_STR2(a,b) COMBINE_STRX(a,b)
#define COMBINE_STR3(a,b,c) COMBINE_STR2(COMBINE_STR2(a,b),c)

/* helper macro to create a section */
#define SECTION_IMPL(name, data) \
.name : \
{ \
data \
}

/* helper macro to create a section with a attribute */
#define SECTION_IMPL_ATTR(name, attr, data) \
.name (attr) : \
{ \
data \
}

/* helper macro to create a alligned section */
#define ALLIGNED_SECTION(name, align, data) \
SECTION_IMPL( \
name, \
. = ALIGN(align); \
data \
)

/* helper macro to create a alligned readonly section */
#define ALLIGNED_READONLY_SECTION(name, align, data) \
SECTION_IMPL_ATTR( \
name, \
READONLY, \
. = ALIGN(align); \
data \
)

/* macro to define the vectors section. Should be pointed to the correct memory region */
#define VECTORS() \
ALLIGNED_READONLY_SECTION( \
vectors, 4, \
KEEP(*(.vectors .vectors.*)); \
)

/* macro to define the rodata section */
#define RODATA() \
ALLIGNED_READONLY_SECTION( \
rodata, 4, \
*(.rodata .rodata.* .gnu.linkonce.r.*); \
)

/* macro to define the stack with a size in bytes */
#define STACK(size) \
.stack (NOLOAD) : \
{ \
. = ALIGN(4); \
/* provide the __stack_start */ \
PROVIDE(__stack_start = .); \
/* add the size in bytes to the current address */ \
. = . + size; \
/* make sure the size is rounded off to 4 bytes */ \
. = ALIGN(4); \
/* provide the __stack_end */ \
PROVIDE(__stack_end = .); \
}

/* macro to define a init array. Array name is passed as an argument */
#define CONSTRUCTOR_SECTION(name) \
.name : \
{ \
. = ALIGN(4); \
PROVIDE(COMBINE_STR3(__,name,_start) = .); \
KEEP(*(SORT(.name.*))) \
KEEP(*(SORT(.name))) \
PROVIDE(COMBINE_STR3(__,name,_end) = .); \
}

/* macro to define a data section. Note: this section is not automaticly loaded.
The secondary loaded needs to be enabled to load this at startup after the
startup code */
#define DATA_SECTION(name, region, storage) \
COMBINE_STR2(.name,_data) : \
{ \
. = ALIGN(4); \
PROVIDE(COMBINE_STR3(__,name,_data_rom_start) = LOADADDR(COMBINE_STR2(.name,_data))); \
PROVIDE(COMBINE_STR3(__,name,_data_start) = .); \
*(SORT_BY_ALIGNMENT(COMBINE_STR2(.name,_data))); \
*(SORT_BY_ALIGNMENT(COMBINE_STR2(.name,_data.*))); \
. = ALIGN(4); \
PROVIDE(COMBINE_STR3(__,name,_data_end) = .); \
} > region AT > storage

/* data section entry for the multi section table */
#define DATA_SECTION_ENTRY(name) \
LONG(COMBINE_STR3(__,name,_data_rom_start)); \
LONG(COMBINE_STR3(__,name,_data_start)); \
LONG(COMBINE_STR3(__,name,_data_end));

/* end marker for the multi section table */
#define DATA_SECTION_ENTRY_END() \
LONG(0); \
LONG(0); \
LONG(0);

/* multisection table to automaticly load the data into the section location */
#define DATA_MULTISECTION_TABLE(entries) \
ALLIGNED_READONLY_SECTION( \
multisection_data, 4, \
PROVIDE(__multisection_data_start = .); \
entries \
PROVIDE(__multisection_data_end = .); \
)

#define BSS_SECTION(name, region) \
COMBINE_STR2(.name,_bss) (NOLOAD) : \
{ \
. = ALIGN(4); \
PROVIDE(COMBINE_STR3(__,name,_bss_start) = .); \
*(SORT_BY_ALIGNMENT(COMBINE_STR2(.name,_bss))); \
*(SORT_BY_ALIGNMENT(COMBINE_STR2(.name,_bss.*))); \
. = ALIGN(4); \
PROVIDE(COMBINE_STR3(__,name,_bss_end) = .); \
} > region

/* bss section entry for the multi section table */
#define BSS_SECTION_ENTRY(name) \
LONG(COMBINE_STR3(__,name,_bss_start)); \
LONG(COMBINE_STR3(__,name,_bss_end));

/* end marker for the multi section table */
#define BSS_SECTION_ENTRY_END() \
LONG(0); \
LONG(0);

/* multisection table to automaticly load all the bss sections to zero */
#define BSS_MULTISECTION_TABLE(entries) \
ALLIGNED_READONLY_SECTION( \
multisection_bss, 4, \
PROVIDE(__multisection_bss_start = .); \
entries \
PROVIDE(__multisection_bss_end = .); \
)
66 changes: 7 additions & 59 deletions targets/chip/atsam3x8e/linkerscript.ld
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,10 @@ SECTIONS
{
/* Vector table. Has the initial stack pointer and the initial
structure for the arm interrupts */
.vectors :
{
. = ALIGN(4);
/* vector table */
KEEP(*(.vectors .vectors.*));
. = ALIGN(4);
} > rom
VECTORS() > rom

/* Text segment, stores all user code */
.text :
.text (READONLY) :
{
. = ALIGN(4);
/* text segment */
Expand All @@ -66,62 +60,16 @@ SECTIONS
} > rom

/* Read only data */
.rodata :
{
. = ALIGN(4);

/* Constands, strings, etc */
*(.rodata .rodata.* .gnu.linkonce.r.*);

. = ALIGN(4);
} > rom
RODATA() > rom

/* Support C constructors, and C destructors in both user code
and the C library. This also provides support for C++ code. */
.preinit_array :
{
. = ALIGN(4);
PROVIDE(__preinit_array_start = .);

KEEP(*(SORT(.preinit_array.*)))
KEEP(*(SORT(.preinit_array)))

PROVIDE(__preinit_array_end = .);
} > rom

.init_array :
{
. = ALIGN(4);
PROVIDE(__init_array_start = .);

KEEP(*(SORT(.init_array.*)))
KEEP(*(SORT(.init_array)))

PROVIDE(__init_array_end = .);
} > rom

.fini_array :
{
. = ALIGN(4);
PROVIDE(__fini_array_start = .);

KEEP(*(SORT(.fini_array.*)))
KEEP(*(SORT(.fini_array)))

PROVIDE(__fini_array_end = .);
} > rom
CONSTRUCTOR_SECTION(preinit_array) > rom
CONSTRUCTOR_SECTION(init_array) > rom
CONSTRUCTOR_SECTION(fini_array) > rom

/* Stack segment */
.stack (NOLOAD) :
{
. = ALIGN(4);
PROVIDE(__stack_start = .);

. = . + STACK_SIZE;
. = ALIGN(4);

PROVIDE(__stack_end = .);
} > ram
STACK(STACK_SIZE) > ram

/* Data that needs to be initialized to a value different than 0 */
.data :
Expand Down
Loading