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 }