/* * Copyright © 2021, Keith Packard * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_MMU #include #endif #define LIBC_BSS K_APP_BMEM(z_libc_partition) #define LIBC_DATA K_APP_DMEM(z_libc_partition) static LIBC_DATA int (*_stdout_hook)(int); int z_impl_zephyr_fputc(int a, FILE *out) { (*_stdout_hook)(a); return 0; } #ifdef CONFIG_USERSPACE static inline int z_vrfy_zephyr_fputc(int c, FILE *stream) { return z_impl_zephyr_fputc(c, stream); } #include #endif static int picolibc_put(char a, FILE *f) { zephyr_fputc(a, f); return 0; } static LIBC_DATA FILE __stdout = FDEV_SETUP_STREAM(picolibc_put, NULL, NULL, 0); static LIBC_DATA FILE __stdin = FDEV_SETUP_STREAM(NULL, NULL, NULL, 0); #ifdef __strong_reference #define STDIO_ALIAS(x) __strong_reference(stdout, x); #else #define STDIO_ALIAS(x) FILE *const x = &__stdout; #endif FILE *const stdin = &__stdin; FILE *const stdout = &__stdout; STDIO_ALIAS(stderr); void __stdout_hook_install(int (*hook)(int)) { _stdout_hook = hook; __stdout.flags |= _FDEV_SETUP_WRITE; } void __stdin_hook_install(unsigned char (*hook)(void)) { __stdin.get = (int (*)(FILE *)) hook; __stdin.flags |= _FDEV_SETUP_READ; } #include struct cb_bits { FILE f; cbprintf_cb out; void *ctx; }; static int cbputc(char c, FILE *_s) { struct cb_bits *s = (struct cb_bits *) _s; (*s->out) (c, s->ctx); return 0; } int cbvprintf(cbprintf_cb out, void *ctx, const char *fp, va_list ap) { struct cb_bits s = { .f = FDEV_SETUP_STREAM(cbputc, NULL, NULL, _FDEV_SETUP_WRITE), .out = out, .ctx = ctx, }; return vfprintf(&s.f, fp, ap); } __weak void _exit(int status) { printk("exit\n"); while (1) { Z_SPIN_DELAY(100); } } #ifdef CONFIG_MULTITHREADING #define _LOCK_T void * K_MUTEX_DEFINE(__lock___libc_recursive_mutex); #ifdef CONFIG_USERSPACE /* Grant public access to picolibc lock after boot */ static int picolibc_locks_prepare(void) { /* Initialise recursive locks */ k_object_access_all_grant(&__lock___libc_recursive_mutex); return 0; } SYS_INIT(picolibc_locks_prepare, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #endif /* CONFIG_USERSPACE */ /* Create a new dynamic recursive lock */ void __retarget_lock_init_recursive(_LOCK_T *lock) { __ASSERT_NO_MSG(lock != NULL); /* Allocate mutex object */ #ifndef CONFIG_USERSPACE *lock = malloc(sizeof(struct k_mutex)); #else *lock = k_object_alloc(K_OBJ_MUTEX); #endif /* !CONFIG_USERSPACE */ __ASSERT(*lock != NULL, "recursive lock allocation failed"); k_mutex_init((struct k_mutex *)*lock); } /* Create a new dynamic non-recursive lock */ void __retarget_lock_init(_LOCK_T *lock) { __retarget_lock_init_recursive(lock); } /* Close dynamic recursive lock */ void __retarget_lock_close_recursive(_LOCK_T lock) { __ASSERT_NO_MSG(lock != NULL); #ifndef CONFIG_USERSPACE free(lock); #else k_object_release(lock); #endif /* !CONFIG_USERSPACE */ } /* Close dynamic non-recursive lock */ void __retarget_lock_close(_LOCK_T lock) { __retarget_lock_close_recursive(lock); } /* Acquiure recursive lock */ void __retarget_lock_acquire_recursive(_LOCK_T lock) { __ASSERT_NO_MSG(lock != NULL); k_mutex_lock((struct k_mutex *)lock, K_FOREVER); } /* Acquiure non-recursive lock */ void __retarget_lock_acquire(_LOCK_T lock) { __retarget_lock_acquire_recursive(lock); } /* Try acquiring recursive lock */ int __retarget_lock_try_acquire_recursive(_LOCK_T lock) { __ASSERT_NO_MSG(lock != NULL); return !k_mutex_lock((struct k_mutex *)lock, K_NO_WAIT); } /* Try acquiring non-recursive lock */ int __retarget_lock_try_acquire(_LOCK_T lock) { return __retarget_lock_try_acquire_recursive(lock); } /* Release recursive lock */ void __retarget_lock_release_recursive(_LOCK_T lock) { __ASSERT_NO_MSG(lock != NULL); k_mutex_unlock((struct k_mutex *)lock); } /* Release non-recursive lock */ void __retarget_lock_release(_LOCK_T lock) { __retarget_lock_release_recursive(lock); } #endif /* CONFIG_MULTITHREADING */ /* This function gets called if static buffer overflow detection is enabled on * stdlib side (Picolibc here), in case such an overflow is detected. Picolibc * provides an implementation not suitable for us, so we override it here. */ __weak FUNC_NORETURN void __chk_fail(void) { printk("* buffer overflow detected *\n"); z_except_reason(K_ERR_STACK_CHK_FAIL); CODE_UNREACHABLE; } #ifndef CONFIG_LIBC_ERRNO /* * Picolibc needs to be able to declare this itself so that the library * doesn't end up needing zephyr header files. That means using a regular * function instead of an inline. */ int *z_errno_wrap(void) { return z_errno(); } #endif