/* * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #if PICO_ENTER_USB_BOOT_ON_EXIT #include "pico/bootrom.h" #endif #include "pico/time.h" #include "pico/runtime_init.h" #if LIB_PICO_PRINTF_PICO #include "pico/printf.h" #else #define weak_raw_printf printf #define weak_raw_vprintf vprintf #endif #if LIB_PICO_STDIO #include "pico/stdio.h" #endif #if PICO_ENTER_USB_BOOT_ON_EXIT #include "pico/bootrom.h" #endif extern char __StackLimit; /* Set by linker. */ #define STDIO_HANDLE_STDIN 0 #define STDIO_HANDLE_STDOUT 1 #define STDIO_HANDLE_STDERR 2 void __attribute__((noreturn)) __weak _exit(__unused int status) { #if PICO_ENTER_USB_BOOT_ON_EXIT reset_usb_boot(0,0); #else while (1) { __breakpoint(); } #endif } __weak void *_sbrk(int incr) { extern char end; /* Set by linker. */ static char *heap_end; char *prev_heap_end; if (heap_end == 0) heap_end = &end; prev_heap_end = heap_end; char *next_heap_end = heap_end + incr; if (__builtin_expect(next_heap_end > (&__StackLimit), false)) { #if PICO_USE_OPTIMISTIC_SBRK if (heap_end == &__StackLimit) { // errno = ENOMEM; return (char *) -1; } next_heap_end = &__StackLimit; #else return (char *) -1; #endif } heap_end = next_heap_end; return (void *) prev_heap_end; } static int64_t epoch_time_us_since_boot; __weak int _gettimeofday (struct timeval *__restrict tv, __unused void *__restrict tz) { if (tv) { int64_t us_since_epoch = ((int64_t)to_us_since_boot(get_absolute_time())) - epoch_time_us_since_boot; tv->tv_sec = (time_t)(us_since_epoch / 1000000); tv->tv_usec = (suseconds_t)(us_since_epoch % 1000000); } return 0; } __weak int settimeofday(__unused const struct timeval *tv, __unused const struct timezone *tz) { if (tv) { int64_t us_since_epoch = tv->tv_sec * 1000000 + tv->tv_usec; epoch_time_us_since_boot = (int64_t)to_us_since_boot(get_absolute_time()) - us_since_epoch; } return 0; } __weak int _times(struct tms *tms) { #if CLOCKS_PER_SEC >= 1000000 tms->tms_utime = (clock_t)(to_us_since_boot(get_absolute_time()) * (CLOCKS_PER_SEC / 1000000)); #else tms->tms_utime = (clock_t)(to_us_since_boot(get_absolute_time()) / (1000000 / CLOCKS_PER_SEC)); #endif tms->tms_stime = 0; tms->tms_cutime = 0; tms->tms_cstime = 0; return 0; } __weak pid_t _getpid(void) { return 0; } __weak int _kill(__unused pid_t pid, __unused int sig) { return -1; } int __attribute__((weak)) _read(int handle, char *buffer, int length) { #if LIB_PICO_STDIO if (handle == STDIO_HANDLE_STDIN) { return stdio_get_until(buffer, length, at_the_end_of_time); } #endif return -1; } int __attribute__((weak)) _write(int handle, char *buffer, int length) { #if LIB_PICO_STDIO if (handle == STDIO_HANDLE_STDOUT || handle == STDIO_HANDLE_STDERR) { stdio_put_string(buffer, length, false, true); return length; } #endif return -1; } int __attribute__((weak)) _open(__unused const char *fn, __unused int oflag, ...) { return -1; } int __attribute__((weak)) _close(__unused int fd) { return -1; } off_t __attribute__((weak)) _lseek(__unused int fd, __unused off_t pos, __unused int whence) { return -1; } int __attribute__((weak)) _fstat(__unused int fd, __unused struct stat *buf) { return -1; } int __attribute__((weak)) _isatty(int fd) { return fd == STDIO_HANDLE_STDIN || fd == STDIO_HANDLE_STDOUT || fd == STDIO_HANDLE_STDERR; } // exit is not useful... no desire to pull in __call_exitprocs void exit(int status) { _exit(status); } // incorrect warning from GCC 6 GCC_Pragma("GCC diagnostic push") GCC_Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=format\"") void __weak __assert_func(const char *file, int line, const char *func, const char *failedexpr) { weak_raw_printf("assertion \"%s\" failed: file \"%s\", line %d%s%s\n", failedexpr, file, line, func ? ", function: " : "", func ? func : ""); _exit(1); } GCC_Pragma("GCC diagnostic pop") void runtime_init(void) { #ifndef NDEBUG if (__get_current_exception()) { // crap; started in exception handler __breakpoint(); } #endif #if !PICO_RUNTIME_SKIP_INIT_PER_CORE_INSTALL_STACK_GUARD // install core0 stack guard extern char __StackBottom; runtime_init_per_core_install_stack_guard(&__StackBottom); #endif // todo maybe we want to do this in the future, but it does stuff like register_tm_clones // which we didn't do in previous SDKs //extern void __libc_init_array(void); //__libc_init_array(); // ... so instead just do the __preinit_array runtime_run_initializers(); // ... and the __init_array extern void (*__init_array_start)(void); extern void (*__init_array_end)(void); for (void (**p)(void) = &__init_array_start; p < &__init_array_end; ++p) { (*p)(); } }