Skip to content

Commit 65fce24

Browse files
committed
added a reset handler
1 parent 851d162 commit 65fce24

2 files changed

Lines changed: 124 additions & 0 deletions

File tree

entry/entry.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#include <stdbool.h>
2+
#include <stdint.h>
3+
4+
// type for constructors
5+
typedef void (*entry_constructor)(void);
6+
7+
// declaration to the main function
8+
int main();
9+
10+
/**
11+
* @brief Reset handler when the target starts running. This function
12+
* initilizes the bss and data segements
13+
*
14+
* @details declares all linker variables as extern. Then we refer to the
15+
* value using the &operator as the variables is at a valid data address.
16+
*
17+
* Functions that need to be called before main are run should have the
18+
* attribute "__constructor__". When marked the function will be added to
19+
* the ".init_array" segment and called before main is called.
20+
*
21+
*/
22+
void __attribute__((__noreturn__, __naked__)) __reset_handler() {
23+
// initialize the stack pointer. As we are running from ram
24+
// the stack pointer is not setup yet. Move it to the stack
25+
// end segment to prevent a hardfault
26+
extern uint32_t __stack_end;
27+
asm volatile ("mov sp, %0" : : "r" (&__stack_end) : );
28+
29+
extern uint8_t __bss_start;
30+
extern uint8_t __bss_end;
31+
32+
// set the bss section to 0x00
33+
for (uint32_t i = 0; i < (&__bss_end - &__bss_start); i++) {
34+
((volatile uint8_t*)(&__bss_start))[i] = 0x00;
35+
}
36+
37+
extern const entry_constructor __preinit_array_start;
38+
extern const entry_constructor __preinit_array_end;
39+
40+
// excecute all the preinit constructors
41+
for (uint32_t i = 0; i < (&__preinit_array_end - &__preinit_array_start); i++) {
42+
// call the preinit calls
43+
(&__preinit_array_start)[i]();
44+
}
45+
46+
extern const entry_constructor __init_array_start;
47+
extern const entry_constructor __init_array_end;
48+
49+
// excecute all the global constructors
50+
for (uint32_t i = 0; i < (&__init_array_end - &__init_array_start); i++) {
51+
// call every constructor we have
52+
(&__init_array_start)[i]();
53+
}
54+
55+
// run main
56+
(void)main();
57+
58+
extern const entry_constructor __fini_array_start;
59+
extern const entry_constructor __fini_array_end;
60+
61+
// run all the destructors. Should never be called but if it happens
62+
// it should work
63+
for (uint32_t i = 0; i < (&__fini_array_end - &__fini_array_start); i++) {
64+
// call every destructor we have
65+
(&__fini_array_start)[i]();
66+
}
67+
68+
// we should never be here. If this happens loop to make
69+
// sure we never exit the reset handler
70+
while (true) {};
71+
}
72+
73+
/**
74+
* @brief Default handler that locks the cpu.
75+
*
76+
*/
77+
void __default_handler() {
78+
// do nothing and wait
79+
while (true) {}
80+
}
81+
82+
// called when a vft entry is not yet filled in
83+
void __cxa_pure_virtual() {}

entry/entry.hpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#ifndef KLIB_ENTRY_HPP
2+
#define KLIB_ENTRY_HPP
3+
4+
#include <stdint.h>
5+
6+
// extern c for c linkage in c++. No ifdef cplusplus as targets
7+
// should be implemented using c++
8+
extern "C" {
9+
// pointer to the end of the stack. Definition is done in the
10+
// linkerscript. Only the address of the variable should be used. The
11+
// address points to the correct location of the variable
12+
extern const uint32_t __stack_end;
13+
14+
// pointer to the start of the heap. Definition is done in the
15+
// linkerscript. Only the address of the variable should be used. The
16+
// address points to the correct location of the variable
17+
extern const uint32_t __heap_start;
18+
19+
// pointer to the end of the heap. Definition is done in the
20+
// linkerscript. Only the address of the variable should be used. The
21+
// address points to the correct location of the variable
22+
extern const uint32_t __heap_end;
23+
24+
/**
25+
* @brief Generic reset handler that initializes the .bss and .data
26+
* segments. It calls all the constructors and runs main. When code
27+
* before main needs to be executed the "__constructor__" attribute
28+
* can be added to the function.
29+
*
30+
*/
31+
void __reset_handler();
32+
33+
/**
34+
* @brief Default handler. Should be used to initialize the default
35+
* arm vector table.
36+
*
37+
*/
38+
void __default_handler();
39+
}
40+
41+
#endif

0 commit comments

Comments
 (0)