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