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