initial commit
This commit is contained in:
101
port/moonlight/bootup.c
Normal file
101
port/moonlight/bootup.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
#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 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.init")));
|
||||
|
||||
// Entry and exit points as C functions.
|
||||
EXTERN_C void _initialize(void) __attribute__ ((noreturn,section(".init")));
|
||||
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_end));
|
||||
// Call constructors
|
||||
for (const function_t* entry=&__init_array_start;
|
||||
entry < &__init_array_end;
|
||||
++entry) {
|
||||
(*entry)();
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user