-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathruntime.c
More file actions
275 lines (232 loc) · 8.58 KB
/
Copy pathruntime.c
File metadata and controls
275 lines (232 loc) · 8.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdarg.h>
#include "pico.h"
#include "hardware/regs/m0plus.h"
#include "hardware/regs/resets.h"
#include "hardware/structs/mpu.h"
#include "hardware/structs/scb.h"
#include "hardware/structs/padsbank0.h"
#include "hardware/clocks.h"
#include "hardware/irq.h"
#include "hardware/resets.h"
#include "pico/mutex.h"
#include "pico/time.h"
#include "pico/printf.h"
#if PICO_ENTER_USB_BOOT_ON_EXIT
#include "pico/bootrom.h"
#endif
#ifndef PICO_NO_RAM_VECTOR_TABLE
#define PICO_NO_RAM_VECTOR_TABLE 0
#endif
extern char __StackLimit; /* Set by linker. */
uint32_t __attribute__((section(".ram_vector_table"))) ram_vector_table[48];
// this is called for each thread since they have their own MPU
void runtime_install_stack_guard(void *stack_bottom) {
// this is called b4 runtime_init is complete, so beware printf or assert
// make sure no one is using the MPU yet
if (mpu_hw->ctrl) {
// Note that it would be tempting to change this to a panic, but it happens so early, printing is not a good idea
__breakpoint();
}
uintptr_t addr = (uintptr_t) stack_bottom;
// the minimum we can protect is 32 bytes on a 32 byte boundary, so round up which will
// just shorten the valid stack range a tad
addr = (addr + 31u) & ~31u;
// mask is 1 bit per 32 bytes of the 256 byte range... clear the bit for the segment we want
uint32_t subregion_select = 0xffu ^ (1u << ((addr >> 5u) & 7u));
mpu_hw->ctrl = 5; // enable mpu with background default map
mpu_hw->rbar = (addr & (uint)~0xff) | 0x8 | 0;
mpu_hw->rasr = 1 // enable region
| (0x7 << 1) // size 2^(7 + 1) = 256
| (subregion_select << 8)
| 0x10000000; // XN = disable instruction fetch; no other bits means no permissions
}
void runtime_init(void) {
// Reset all peripherals to put system into a known state,
// - except for QSPI pads and the XIP IO bank, as this is fatal if running from flash
// - and the PLLs, as this is fatal if clock muxing has not been reset on this boot
// - and USB, syscfg, as this disturbs USB-to-SWD on core 1
reset_block(~(
RESETS_RESET_IO_QSPI_BITS |
RESETS_RESET_PADS_QSPI_BITS |
RESETS_RESET_PLL_USB_BITS |
RESETS_RESET_USBCTRL_BITS |
RESETS_RESET_SYSCFG_BITS |
RESETS_RESET_PLL_SYS_BITS
));
// Remove reset from peripherals which are clocked only by clk_sys and
// clk_ref. Other peripherals stay in reset until we've configured clocks.
unreset_block_wait(RESETS_RESET_BITS & ~(
RESETS_RESET_ADC_BITS |
RESETS_RESET_RTC_BITS |
RESETS_RESET_SPI0_BITS |
RESETS_RESET_SPI1_BITS |
RESETS_RESET_UART0_BITS |
RESETS_RESET_UART1_BITS |
RESETS_RESET_USBCTRL_BITS
));
// pre-init runs really early since we need it even for memcpy and divide!
// (basically anything in aeabi that uses bootrom)
// Start and end points of the constructor list,
// defined by the linker script.
extern void (*__preinit_array_start)(void);
extern void (*__preinit_array_end)(void);
// Call each function in the list.
// We have to take the address of the symbols, as __preinit_array_start *is*
// the first function pointer, not the address of it.
for (void (**p)(void) = &__preinit_array_start; p < &__preinit_array_end; ++p) {
(*p)();
}
// After calling preinit we have enough runtime to do the exciting maths
// in clocks_init
clocks_init();
// Peripheral clocks should now all be running
unreset_block_wait(RESETS_RESET_BITS);
#if !PICO_IE_26_29_UNCHANGED_ON_RESET
// after resetting BANK0 we should disable IE on 26-29
hw_clear_alias(padsbank0_hw)->io[26] = hw_clear_alias(padsbank0_hw)->io[27] =
hw_clear_alias(padsbank0_hw)->io[28] = hw_clear_alias(padsbank0_hw)->io[29] = PADS_BANK0_GPIO0_IE_BITS;
#endif
extern mutex_t __mutex_array_start;
extern mutex_t __mutex_array_end;
// the first function pointer, not the address of it.
for (mutex_t *m = &__mutex_array_start; m < &__mutex_array_end; m++) {
if (m->recursion_state) {
recursive_mutex_init(m);
} else {
mutex_init(m);
}
}
#if !(PICO_NO_RAM_VECTOR_TABLE || PICO_NO_FLASH)
__builtin_memcpy(ram_vector_table, (uint32_t *) scb_hw->vtor, sizeof(ram_vector_table));
scb_hw->vtor = (uintptr_t) ram_vector_table;
#endif
#ifndef NDEBUG
if (__get_current_exception()) {
// crap; started in exception handler
__asm ("bkpt #0");
}
#endif
#if PICO_USE_STACK_GUARDS
// install core0 stack guard
extern char __StackBottom;
runtime_install_stack_guard(&__StackBottom);
#endif
spin_locks_reset();
irq_init_priorities();
alarm_pool_init_default();
// Start and end points of the constructor list,
// defined by the linker script.
extern void (*__init_array_start)(void);
extern void (*__init_array_end)(void);
// Call each function in the list.
// We have to take the address of the symbols, as __init_array_start *is*
// the first function pointer, not the address of it.
for (void (**p)(void) = &__init_array_start; p < &__init_array_end; ++p) {
(*p)();
}
}
void _exit(__unused int status) {
#if PICO_ENTER_USB_BOOT_ON_EXIT
reset_usb_boot(0,0);
#else
while (1) {
__breakpoint();
}
#endif
}
void *_sbrk(int incr) {
extern char end; /* Set by linker. */
static char *heap_end;
char *prev_heap_end;
if (heap_end == 0)
heap_end = &end;
prev_heap_end = heap_end;
char *next_heap_end = heap_end + incr;
if (__builtin_expect(next_heap_end > (&__StackLimit), false)) {
#if PICO_USE_OPTIMISTIC_SBRK
if (heap_end == &__StackLimit) {
// errno = ENOMEM;
return (char *) -1;
}
next_heap_end = &__StackLimit;
#else
return (char *) -1;
#endif
}
heap_end = next_heap_end;
return (void *) prev_heap_end;
}
// exit is not useful... no desire to pull in __call_exitprocs
void exit(int status) {
_exit(status);
}
// incorrect warning from GCC 6
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
void __assert_func(const char *file, int line, const char *func, const char *failedexpr) {
weak_raw_printf("assertion \"%s\" failed: file \"%s\", line %d%s%s\n",
failedexpr, file, line, func ? ", function: " : "",
func ? func : "");
_exit(1);
}
#pragma GCC diagnostic pop
void __attribute__((noreturn)) panic_unsupported() {
panic("not supported");
}
// PICO_CONFIG: PICO_PANIC_FUNCTION, Name of a function to use in place of the stock panic function or empty string to simply breakpoint on panic, group=pico_runtime
// note the default is not "panic" it is undefined
#ifdef PICO_PANIC_FUNCTION
#define PICO_PANIC_FUNCTION_EMPTY (__CONCAT(PICO_PANIC_FUNCTION, 1) == 1)
#if !PICO_PANIC_FUNCTION_EMPTY
extern void __attribute__((noreturn)) __printflike(1, 0) PICO_PANIC_FUNCTION(__unused const char *fmt, ...);
#endif
// Use a forwarding method here as it is a little simpler than renaming the symbol as it is used from assembler
void __attribute__((naked, noreturn)) __printflike(1, 0) panic(__unused const char *fmt, ...) {
// if you get an undefined reference here, you didn't define your PICO_PANIC_FUNCTION!
asm (
"push {lr}\n"
#if !PICO_PANIC_FUNCTION_EMPTY
"bl " __XSTRING(PICO_PANIC_FUNCTION) "\n"
#endif
"bkpt #0\n"
"1: b 1b\n" // loop for ever as we are no return
:
:
:
);
}
#else
// todo consider making this try harder to output if we panic early
// right now, print mutex may be uninitialised (in which case it deadlocks - although after printing "PANIC")
// more importantly there may be no stdout/UART initialized yet
// todo we may want to think about where we print panic messages to; writing to USB appears to work
// though it doesn't seem like we can expect it to... fine for now
void __attribute__((noreturn)) __printflike(1, 0) panic(const char *fmt, ...) {
puts("\n*** PANIC ***\n");
if (fmt) {
#if LIB_PICO_PRINTF_NONE
puts(fmt);
#else
va_list args;
va_start(args, fmt);
#if PICO_PRINTF_ALWAYS_INCLUDED
vprintf(fmt, args);
#else
weak_raw_vprintf(fmt, args);
#endif
va_end(args);
puts("\n");
#endif
}
_exit(1);
}
#endif
void hard_assertion_failure(void) {
panic("Hard assert");
}