This change updates the linker script and dependend wile so that thread local storage sections are properly supported and initailaized
111 lines
3.5 KiB
C
111 lines
3.5 KiB
C
/*
|
|
Simple C++ startup routine to setup CRT
|
|
SPDX-License-Identifier: Unlicense
|
|
|
|
(https://five-embeddev.com/ | http://www.shincbm.com/)
|
|
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <picotls.h>
|
|
|
|
#ifdef __cplusplus
|
|
#define EXTERN_C extern "C"
|
|
#else
|
|
#define EXTERN_C extern
|
|
#endif
|
|
|
|
// Generic C function pointer.
|
|
typedef void(*function_t)(void) ;
|
|
// These symbols are defined by the linker script.
|
|
// See linker.lds
|
|
EXTERN_C uint8_t __bss_start;
|
|
EXTERN_C uint8_t __bss_end;
|
|
EXTERN_C const uint8_t __data_source;
|
|
EXTERN_C uint8_t __data_start;
|
|
EXTERN_C uint8_t __data_end;
|
|
EXTERN_C const uint8_t __data_source;
|
|
EXTERN_C uint8_t __tbss_start;
|
|
EXTERN_C uintptr_t __tbss_size;
|
|
EXTERN_C const uint8_t __tdata_source;
|
|
EXTERN_C uint8_t __tls_base;
|
|
EXTERN_C uintptr_t __tdata_size;
|
|
|
|
EXTERN_C function_t __init_array_start;
|
|
EXTERN_C function_t __init_array_end;
|
|
EXTERN_C function_t __fini_array_start;
|
|
EXTERN_C function_t __fini_array_end;
|
|
|
|
// This function will be placed by the linker script according to the section
|
|
// Raw function 'called' by the CPU with no runtime.
|
|
EXTERN_C void _start(void) __attribute__ ((naked,section(".text.boot")));
|
|
|
|
// Entry and exit points as C functions.
|
|
EXTERN_C void _initialize(void) __attribute__ ((noreturn,section(".text.boot")));
|
|
EXTERN_C void _exit(int exit_code) __attribute__ ((noreturn,noinline,weak));
|
|
|
|
// Standard entry point, no arguments.
|
|
extern int main(void);
|
|
|
|
// The linker script will place this in the reset entry point.
|
|
// It will be 'called' with no stack or C runtime configuration.
|
|
// NOTE - this only supports a single hart.
|
|
// tp will not be initialized
|
|
void _start(void) {
|
|
// Setup SP and GP
|
|
// The locations are defined in the linker script
|
|
__asm__ volatile (
|
|
".option push;"
|
|
// The 'norelax' option is critical here.
|
|
// Without 'norelax' the global pointer will
|
|
// be loaded relative to the global pointer!
|
|
".option norelax;"
|
|
"la gp, __global_pointer$;"
|
|
".option pop;"
|
|
"la sp, _sp;"
|
|
"jal zero, _initialize;"
|
|
: /* output: none %0 */
|
|
: /* input: none */
|
|
: /* clobbers: none */);
|
|
// This point will not be executed, _initialize() will be called with no return.
|
|
}
|
|
|
|
// At this point we have a stack and global poiner, but no access to global variables.
|
|
void _initialize(void) {
|
|
// Init memory regions
|
|
// Clear the .bss section (global variables with no initial values)
|
|
memset((void*) &__bss_start, 0, (&__bss_end - &__bss_start));
|
|
// Initialize the .data section (global variables with initial values)
|
|
memcpy((void*)&__data_start, (const void*)&__data_source, (&__data_end - &__data_start));
|
|
// Clear the .tbss section (thread local variables with no initial values)
|
|
memset((void*) &__tbss_start, 0, __tbss_size);
|
|
// Initialize the .tls section (thread local variables with initial values)
|
|
memcpy((void*) &__tls_base, (const void*)&__tdata_source, __tdata_size);
|
|
// Call constructors
|
|
for (const function_t* entry=&__init_array_start;
|
|
entry < &__init_array_end;
|
|
++entry) {
|
|
(*entry)();
|
|
}
|
|
#ifdef __THREAD_LOCAL_STORAGE
|
|
_set_tls(__tls_base)
|
|
#endif
|
|
int rc = main();
|
|
// Call destructors
|
|
for (const function_t* entry=&__fini_array_start;
|
|
entry < &__fini_array_end;
|
|
++entry) {
|
|
(*entry)();
|
|
}
|
|
_exit(rc);
|
|
}
|
|
|
|
// This should never be called. Busy loop with the CPU in idle state.
|
|
void _exit(int exit_code) {
|
|
(void)exit_code;
|
|
// Halt
|
|
while (1) {
|
|
__asm__ volatile ("wfi");
|
|
}
|
|
} |