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 <stdlib.h>
9 #include <unistd.h>
10 #include <sys/time.h>
11 #include <sys/times.h>
12
13 #include "pico.h"
14 #if LIB_PICO_STDIO
15 #include "pico/stdio.h"
16 #endif
17
18 #if PICO_ENTER_USB_BOOT_ON_EXIT
19 #include "pico/bootrom.h"
20 #endif
21
22 #include "pico/time.h"
23 #include "pico/runtime_init.h"
24
25 #if LIB_PICO_PRINTF_PICO
26 #include "pico/printf.h"
27 #else
28 #define weak_raw_printf printf
29 #define weak_raw_vprintf vprintf
30 #endif
31
picolibc_putc(char c,__unused FILE * file)32 static int picolibc_putc(char c, __unused FILE *file) {
33 #if LIB_PICO_STDIO
34 stdio_putchar(c);
35 #endif
36 return c;
37 }
38
picolibc_getc(__unused FILE * file)39 static int picolibc_getc(__unused FILE *file) {
40 #if LIB_PICO_STDIO
41 return stdio_getchar();
42 #endif
43 return -1;
44 }
45
picolibc_flush(__unused FILE * file)46 static int picolibc_flush(__unused FILE *file) {
47 #if LIB_PICO_STDIO
48 stdio_flush();
49 #endif
50 return 0;
51 }
52
53 static FILE __stdio = FDEV_SETUP_STREAM(picolibc_putc,
54 picolibc_getc,
55 picolibc_flush,
56 _FDEV_SETUP_RW);
57
58 FILE *const stdin = &__stdio; __strong_reference(stdin, stdout); __strong_reference(stdin, stderr);
59
__assert_func(const char * file,int line,const char * func,const char * failedexpr)60 void __weak __assert_func(const char *file, int line, const char *func, const char *failedexpr) {
61 weak_raw_printf("assertion \"%s\" failed: file \"%s\", line %d%s%s\n",
62 failedexpr, file, line, func ? ", function: " : "",
63 func ? func : "");
64
65 _exit(1);
66 }
67
68
_exit(__unused int status)69 void __attribute__((noreturn)) __weak _exit(__unused int status) {
70 #if PICO_ENTER_USB_BOOT_ON_EXIT
71 reset_usb_boot(0,0);
72 #else
73 while (1) {
74 __breakpoint();
75 }
76 #endif
77 }
78
79 static int64_t epoch_time_us_since_boot;
80
gettimeofday(struct timeval * __restrict tv,__unused void * __restrict tz)81 __weak int gettimeofday (struct timeval *__restrict tv, __unused void *__restrict tz) {
82 if (tv) {
83 int64_t us_since_epoch = ((int64_t)to_us_since_boot(get_absolute_time())) - epoch_time_us_since_boot;
84 tv->tv_sec = (time_t)(us_since_epoch / 1000000);
85 tv->tv_usec = (suseconds_t)(us_since_epoch % 1000000);
86 }
87 return 0;
88 }
89
settimeofday(__unused const struct timeval * tv,__unused const struct timezone * tz)90 __weak int settimeofday(__unused const struct timeval *tv, __unused const struct timezone *tz) {
91 if (tv) {
92 int64_t us_since_epoch = tv->tv_sec * 1000000 + tv->tv_usec;
93 epoch_time_us_since_boot = (int64_t)to_us_since_boot(get_absolute_time()) - us_since_epoch;
94 }
95 return 0;
96 }
97
times(struct tms * tms)98 __weak clock_t times(struct tms *tms) {
99 #if CLOCKS_PER_SEC >= 1000000
100 tms->tms_utime = (clock_t)(to_us_since_boot(get_absolute_time()) * (CLOCKS_PER_SEC / 1000000));
101 #else
102 tms->tms_utime = (clock_t)(to_us_since_boot(get_absolute_time()) / (1000000 / CLOCKS_PER_SEC));
103 #endif
104 tms->tms_stime = 0;
105 tms->tms_cutime = 0;
106 tms->tms_cstime = 0;
107 return 0;
108 }
109
runtime_init(void)110 void runtime_init(void) {
111 #ifndef NDEBUG
112 if (__get_current_exception()) {
113 // crap; started in exception handler
114 __breakpoint();
115 }
116 #endif
117
118 #if !PICO_RUNTIME_SKIP_INIT_PER_CORE_INSTALL_STACK_GUARD
119 // install core0 stack guard
120 extern char __StackBottom;
121 runtime_init_per_core_install_stack_guard(&__StackBottom);
122 #endif
123
124 // piolibc __libc_init_array does __preint_array and __init_array
125 extern void __libc_init_array(void);
126 __libc_init_array();
127 }
128
129 #if !PICO_RUNTIME_NO_INIT_PER_CORE_TLS_SETUP
runtime_init_pre_core_tls_setup(void)130 __weak void runtime_init_pre_core_tls_setup(void) {
131 // for now we just set the same global area on both cores
132 // note: that this is superfluous with the stock picolibc it seems, since it is itself
133 // using a version of __aeabi_read_tp that returns the same pointer on both cores
134 extern char __tls_base[];
135 extern void _set_tls(void *tls);
136 _set_tls(__tls_base);
137 }
138 #endif
139
140 #if !PICO_RUNTIME_SKIP_INIT_PER_CORE_TLS_SETUP
141 PICO_RUNTIME_INIT_FUNC_PER_CORE(runtime_init_pre_core_tls_setup, PICO_RUNTIME_INIT_PER_CORE_TLS_SETUP);
142 #endif
143
144 //// naked as it must preserve everything except r0 and lr
145 //uint32_t __attribute__((naked)) WRAPPER_FUNC(__aeabi_read_tp)() {
146 // // note for now we are just returning a shared instance on both cores
147 // pico_default_asm_volatile(
148 // "ldr r0, =__tls_base\n"
149 // "bx lr\n"
150 // );
151 //}