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/stat.h>
10 #include <sys/time.h>
11 #include <sys/times.h>
12 #include <time.h>
13 #include <unistd.h>
14 #if PICO_ENTER_USB_BOOT_ON_EXIT
15 #include "pico/bootrom.h"
16 #endif
17 #include "pico/time.h"
18 #include "pico/runtime_init.h"
19
20 #if LIB_PICO_PRINTF_PICO
21 #include "pico/printf.h"
22 #else
23 #define weak_raw_printf printf
24 #define weak_raw_vprintf vprintf
25 #endif
26 #if LIB_PICO_STDIO
27 #include "pico/stdio.h"
28 #endif
29
30 #if PICO_ENTER_USB_BOOT_ON_EXIT
31 #include "pico/bootrom.h"
32 #endif
33
34 extern char __StackLimit; /* Set by linker. */
35
36 #define STDIO_HANDLE_STDIN 0
37 #define STDIO_HANDLE_STDOUT 1
38 #define STDIO_HANDLE_STDERR 2
39
_exit(__unused int status)40 void __attribute__((noreturn)) __weak _exit(__unused int status) {
41 #if PICO_ENTER_USB_BOOT_ON_EXIT
42 reset_usb_boot(0,0);
43 #else
44 while (1) {
45 __breakpoint();
46 }
47 #endif
48 }
49
_sbrk(int incr)50 __weak void *_sbrk(int incr) {
51 extern char end; /* Set by linker. */
52 static char *heap_end;
53 char *prev_heap_end;
54
55 if (heap_end == 0)
56 heap_end = &end;
57
58 prev_heap_end = heap_end;
59 char *next_heap_end = heap_end + incr;
60
61 if (__builtin_expect(next_heap_end > (&__StackLimit), false)) {
62 #if PICO_USE_OPTIMISTIC_SBRK
63 if (heap_end == &__StackLimit) {
64 // errno = ENOMEM;
65 return (char *) -1;
66 }
67 next_heap_end = &__StackLimit;
68 #else
69 return (char *) -1;
70 #endif
71 }
72
73 heap_end = next_heap_end;
74 return (void *) prev_heap_end;
75 }
76
77 static int64_t epoch_time_us_since_boot;
78
_gettimeofday(struct timeval * __restrict tv,__unused void * __restrict tz)79 __weak int _gettimeofday (struct timeval *__restrict tv, __unused void *__restrict tz) {
80 if (tv) {
81 int64_t us_since_epoch = ((int64_t)to_us_since_boot(get_absolute_time())) - epoch_time_us_since_boot;
82 tv->tv_sec = (time_t)(us_since_epoch / 1000000);
83 tv->tv_usec = (suseconds_t)(us_since_epoch % 1000000);
84 }
85 return 0;
86 }
87
settimeofday(__unused const struct timeval * tv,__unused const struct timezone * tz)88 __weak int settimeofday(__unused const struct timeval *tv, __unused const struct timezone *tz) {
89 if (tv) {
90 int64_t us_since_epoch = tv->tv_sec * 1000000 + tv->tv_usec;
91 epoch_time_us_since_boot = (int64_t)to_us_since_boot(get_absolute_time()) - us_since_epoch;
92 }
93 return 0;
94 }
95
_times(struct tms * tms)96 __weak int _times(struct tms *tms) {
97 #if CLOCKS_PER_SEC >= 1000000
98 tms->tms_utime = (clock_t)(to_us_since_boot(get_absolute_time()) * (CLOCKS_PER_SEC / 1000000));
99 #else
100 tms->tms_utime = (clock_t)(to_us_since_boot(get_absolute_time()) / (1000000 / CLOCKS_PER_SEC));
101 #endif
102 tms->tms_stime = 0;
103 tms->tms_cutime = 0;
104 tms->tms_cstime = 0;
105 return 0;
106 }
107
_getpid(void)108 __weak pid_t _getpid(void) {
109 return 0;
110 }
111
_kill(__unused pid_t pid,__unused int sig)112 __weak int _kill(__unused pid_t pid, __unused int sig) {
113 return -1;
114 }
115
_read(int handle,char * buffer,int length)116 int __attribute__((weak)) _read(int handle, char *buffer, int length) {
117 #if LIB_PICO_STDIO
118 if (handle == STDIO_HANDLE_STDIN) {
119 return stdio_get_until(buffer, length, at_the_end_of_time);
120 }
121 #endif
122 return -1;
123 }
124
_write(int handle,char * buffer,int length)125 int __attribute__((weak)) _write(int handle, char *buffer, int length) {
126 #if LIB_PICO_STDIO
127 if (handle == STDIO_HANDLE_STDOUT || handle == STDIO_HANDLE_STDERR) {
128 stdio_put_string(buffer, length, false, true);
129 return length;
130 }
131 #endif
132 return -1;
133 }
134
_open(__unused const char * fn,__unused int oflag,...)135 int __attribute__((weak)) _open(__unused const char *fn, __unused int oflag, ...) {
136 return -1;
137 }
138
_close(__unused int fd)139 int __attribute__((weak)) _close(__unused int fd) {
140 return -1;
141 }
142
_lseek(__unused int fd,__unused off_t pos,__unused int whence)143 off_t __attribute__((weak)) _lseek(__unused int fd, __unused off_t pos, __unused int whence) {
144 return -1;
145 }
146
_fstat(__unused int fd,__unused struct stat * buf)147 int __attribute__((weak)) _fstat(__unused int fd, __unused struct stat *buf) {
148 return -1;
149 }
150
_isatty(int fd)151 int __attribute__((weak)) _isatty(int fd) {
152 return fd == STDIO_HANDLE_STDIN || fd == STDIO_HANDLE_STDOUT || fd == STDIO_HANDLE_STDERR;
153 }
154
155 // exit is not useful... no desire to pull in __call_exitprocs
exit(int status)156 void exit(int status) {
157 _exit(status);
158 }
159
160 // incorrect warning from GCC 6
161 GCC_Pragma("GCC diagnostic push")
162 GCC_Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=format\"")
__assert_func(const char * file,int line,const char * func,const char * failedexpr)163 void __weak __assert_func(const char *file, int line, const char *func, const char *failedexpr) {
164 weak_raw_printf("assertion \"%s\" failed: file \"%s\", line %d%s%s\n",
165 failedexpr, file, line, func ? ", function: " : "",
166 func ? func : "");
167
168 _exit(1);
169 }
170 GCC_Pragma("GCC diagnostic pop")
171
runtime_init(void)172 void runtime_init(void) {
173 #ifndef NDEBUG
174 if (__get_current_exception()) {
175 // crap; started in exception handler
176 __breakpoint();
177 }
178 #endif
179
180 #if !PICO_RUNTIME_SKIP_INIT_PER_CORE_INSTALL_STACK_GUARD
181 // install core0 stack guard
182 extern char __StackBottom;
183 runtime_init_per_core_install_stack_guard(&__StackBottom);
184 #endif
185
186 // todo maybe we want to do this in the future, but it does stuff like register_tm_clones
187 // which we didn't do in previous SDKs
188 //extern void __libc_init_array(void);
189 //__libc_init_array();
190
191 // ... so instead just do the __preinit_array
192 runtime_run_initializers();
193 // ... and the __init_array
194 extern void (*__init_array_start)(void);
195 extern void (*__init_array_end)(void);
196 for (void (**p)(void) = &__init_array_start; p < &__init_array_end; ++p) {
197 (*p)();
198 }
199 }