1 /*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <math.h>
8 #include <stddef.h>
9 #include <sys/time.h>
10
11 #include <llvm-libc-types/ssize_t.h>
12
13 #include "pico/runtime_init.h"
14 #include "pico/stdio.h"
15 #include "pico/time.h"
16
17 #if PICO_ENTER_USB_BOOT_ON_EXIT
18 #include "pico/bootrom.h"
19 #endif
20
21 // These functions are defined by POSIX and not C standard.
22
23 static int64_t epoch_time_us_since_boot;
24
gettimeofday(struct timeval * __restrict tv,__unused struct timezone * __restrict tz)25 int gettimeofday(struct timeval *__restrict tv, __unused struct timezone *__restrict tz) {
26 if (tv) {
27 int64_t us_since_epoch = ((int64_t)to_us_since_boot(get_absolute_time())) - epoch_time_us_since_boot;
28 tv->tv_sec = (time_t)(us_since_epoch / 1000000);
29 tv->tv_usec = (suseconds_t)(us_since_epoch % 1000000);
30 }
31 return 0;
32 }
33
settimeofday(__unused const struct timeval * tv,__unused const struct timezone * tz)34 int settimeofday(__unused const struct timeval *tv, __unused const struct timezone *tz) {
35 if (tv) {
36 int64_t us_since_epoch = tv->tv_sec * 1000000 + tv->tv_usec;
37 epoch_time_us_since_boot = (int64_t)to_us_since_boot(get_absolute_time()) - us_since_epoch;
38 }
39 return 0;
40 }
41
42 // TODO: This should be a thread-local variable.
43 int errno;
44
__llvm_libc_errno(void)45 int *__llvm_libc_errno(void) { return &errno; }
46
47 struct __llvm_libc_stdio_cookie {};
48
49 struct __llvm_libc_stdio_cookie __llvm_libc_stdin_cookie;
50 struct __llvm_libc_stdio_cookie __llvm_libc_stdout_cookie;
51 struct __llvm_libc_stdio_cookie __llvm_libc_stderr_cookie;
52
__llvm_libc_stdio_read(__unused void * cookie,char * buf,size_t size)53 ssize_t __llvm_libc_stdio_read(__unused void *cookie, char *buf, size_t size) {
54 for (size_t i = 0; i < size; i++) {
55 buf[i] = getchar_timeout_us(0);
56 }
57 return size;
58 }
59
__llvm_libc_stdio_write(__unused void * cookie,const char * buf,size_t size)60 ssize_t __llvm_libc_stdio_write(__unused void *cookie, const char *buf, size_t size) {
61 // TODO: We would ideally use `stdio_put_string` from pico_stdio.
62 for (size_t i = 0; i < size; i++) {
63 putchar_raw(buf[i]);
64 }
65 return size;
66 }
67
__cxa_finalize(__unused void * dso)68 void __cxa_finalize(__unused void *dso) {}
69
__llvm_libc_exit(__unused int status)70 void __attribute__((noreturn)) __llvm_libc_exit(__unused int status) {
71 #if PICO_ENTER_USB_BOOT_ON_EXIT
72 reset_usb_boot(0,0);
73 #else
74 while (1) {
75 __breakpoint();
76 }
77 #endif
78 }
79
80 void _exit(int) __attribute__((noreturn, alias("__llvm_libc_exit")));
81
runtime_init(void)82 void runtime_init(void) {
83 #ifndef NDEBUG
84 if (__get_current_exception()) {
85 // crap; started in exception handler
86 __breakpoint();
87 }
88 #endif
89
90 #if !PICO_RUNTIME_SKIP_INIT_PER_CORE_INSTALL_STACK_GUARD
91 // install core0 stack guard
92 extern char __StackBottom;
93 runtime_init_per_core_install_stack_guard(&__StackBottom);
94 #endif
95
96 // todo maybe we want to do this in the future, but it does stuff like register_tm_clones
97 // which we didn't do in previous SDKs
98 //extern void __libc_init_array(void);
99 //__libc_init_array();
100
101 // ... so instead just do the __preinit_array
102 runtime_run_initializers();
103 // ... and the __init_array
104 extern void (*__init_array_start)(void);
105 extern void (*__init_array_end)(void);
106 for (void (**p)(void) = &__init_array_start; p < &__init_array_end; ++p) {
107 (*p)();
108 }
109 }
110
111