Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/zephyr/posix/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ extern "C" {
/* File related operations */
int close(int file);
ssize_t write(int file, const void *buffer, size_t count);
ssize_t pwrite(int file, const void *buffer, size_t count, off_t offset);
ssize_t read(int file, void *buffer, size_t count);
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
off_t lseek(int file, off_t offset, int whence);
int fsync(int fd);
int ftruncate(int fd, off_t length);
Expand Down
7 changes: 7 additions & 0 deletions include/zephyr/sys/fdtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define ZEPHYR_INCLUDE_SYS_FDTABLE_H_

#include <stdarg.h>
#include <stdio.h>
#include <time.h>

/* FIXME: For native_posix ssize_t, off_t. */
Expand Down Expand Up @@ -261,6 +262,12 @@ __syscall int zvfs_select(int nfds, struct zvfs_fd_set *ZRESTRICT readfds,
struct zvfs_fd_set *ZRESTRICT errorfds,
const struct timespec *ZRESTRICT timeout, const void *ZRESTRICT sigmask);

void zvfs_libc_file_alloc_cb(int fd, const char *mode, FILE *fp);
int zvfs_libc_file_alloc(int fd, const char *mode, FILE **fp, k_timeout_t timeout);
void zvfs_libc_file_free(FILE *fp);
int zvfs_libc_file_get_fd(FILE *fp);
FILE *zvfs_libc_file_from_fd(int fd);

/**
* Request codes for fd_op_vtable.ioctl().
*
Expand Down
16 changes: 9 additions & 7 deletions kernel/mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,18 +114,20 @@ int z_impl_k_mutex_lock(struct k_mutex *mutex, k_timeout_t timeout)

key = k_spin_lock(&lock);

if (likely((mutex->lock_count == 0U) || (mutex->owner == _current))) {
if (likely((mutex->lock_count == 0U) || (mutex->owner == _current) ||
(mutex->owner == NULL))) {
if (mutex->owner == NULL) {
mutex->owner = _current;
}

mutex->owner_orig_prio = (mutex->lock_count == 0U) ?
_current->base.prio :
mutex->owner_orig_prio;
mutex->owner_orig_prio =
(mutex->lock_count == 0U) ? _current->base.prio : mutex->owner_orig_prio;

mutex->lock_count++;
mutex->owner = _current;

LOG_DBG("%p took mutex %p, count: %d, orig prio: %d",
_current, mutex, mutex->lock_count,
mutex->owner_orig_prio);
LOG_DBG("%p took mutex %p, count: %d, orig prio: %d", _current, mutex,
mutex->lock_count, mutex->owner_orig_prio);

k_spin_unlock(&lock, key);

Expand Down
1 change: 1 addition & 0 deletions lib/libc/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_THRD
source/thrd/tss.c
)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_REMOVE source/stdio/remove.c)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_FCLOSE source/stdio/fclose.c)

# Prevent compiler from optimizing calloc into an infinite recursive call
zephyr_library_compile_options($<TARGET_PROPERTY:compiler,no_builtin_malloc>)
8 changes: 7 additions & 1 deletion lib/libc/common/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ config COMMON_LIBC_THRD
depends on DYNAMIC_THREAD
# Note: the POSIX_API dependency is only necessary until common elements
# of C11 threads and POSIX API can be abstracted out to a common library.
depends on POSIX_API
depends on POSIX_THREADS
default y
help
Common implementation of C11 <threads.h> API.
Expand All @@ -120,3 +120,9 @@ config COMMON_LIBC_REMOVE
default y if FILE_SYSTEM
help
Common implementation of remove().

config COMMON_LIBC_FCLOSE
bool "Common C library fclose"
default y if ZVFS && !MINIMAL_LIBC
help
Enable the common C library implementation of fclose()
25 changes: 25 additions & 0 deletions lib/libc/common/source/stdio/fclose.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2025 Antmicro <www.antmicro.com>
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/sys/fdtable.h>
#include <unistd.h>

int fclose(FILE *stream)
{
int fd;

fflush(stream);
fd = zvfs_libc_file_get_fd(stream);

if (!fd) {
return EOF;
}
if (close(fd)) {
return EOF;
}

return 0;
}
2 changes: 2 additions & 0 deletions lib/libc/newlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
zephyr_library()
zephyr_library_sources(libc-hooks.c)

zephyr_library_sources_ifdef(CONFIG_ZVFS zvfs_libc.c)

# Do not allow LTO when compiling libc-hooks.c file
set_source_files_properties(libc-hooks.c PROPERTIES COMPILE_OPTIONS $<TARGET_PROPERTY:compiler,prohibit_lto>)

Expand Down
8 changes: 8 additions & 0 deletions lib/libc/newlib/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,12 @@ config NEWLIB_LIBC_CUSTOM_SBRK
Allow user to define custom version of the _sbrk function. Some application
may need to use the remaining RAM for also other purposes than heap.

if ZVFS

config ZVFS_LIBC_FILE_SIZE
default 184 if 64BIT
default 104

endif # ZVFS

endif # NEWLIB_LIBC
2 changes: 2 additions & 0 deletions lib/libc/newlib/libc-hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ static int (*_stdout_hook)(int) = _stdout_hook_default;
void __stdout_hook_install(int (*hook)(int))
{
_stdout_hook = hook;
stdout->_file = 1; /* STDOUT_FILENO */
}

static unsigned char _stdin_hook_default(void)
Expand All @@ -181,6 +182,7 @@ static unsigned char (*_stdin_hook)(void) = _stdin_hook_default;
void __stdin_hook_install(unsigned char (*hook)(void))
{
_stdin_hook = hook;
stdin->_file = 0; /* STDIN_FILENO */
}

int z_impl_zephyr_read_stdin(char *buf, int nbytes)
Expand Down
82 changes: 82 additions & 0 deletions lib/libc/newlib/zvfs_libc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2024 Tenstorrent AI ULC
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#include <zephyr/sys/fdtable.h>
#include <zephyr/toolchain.h>

BUILD_ASSERT(CONFIG_ZVFS_LIBC_FILE_SIZE == sizeof(__FILE),
"CONFIG_ZVFS_LIBC_FILE_SIZE must match size of FILE object");
BUILD_ASSERT(CONFIG_ZVFS_LIBC_FILE_ALIGN == __alignof(__FILE),
"CONFIG_ZVFS_LIBC_FILE_SIZE must match alignment of FILE object");

static int z_libc_sflags(const char *mode)
{
int ret = 0;

switch (mode[0]) {
case 'r':
ret = ZVFS_O_RDONLY;
break;

case 'w':
ret = ZVFS_O_WRONLY | ZVFS_O_CREAT | ZVFS_O_TRUNC;
break;

case 'a':
ret = ZVFS_O_WRONLY | ZVFS_O_CREAT | ZVFS_O_APPEND;
break;
default:
return 0;
}

while (*++mode) {
switch (*mode) {
case '+':
ret |= ZVFS_O_RDWR;
break;
case 'x':
ret |= ZVFS_O_EXCL;
break;
default:
break;
}
}

return ret;
}

void zvfs_libc_file_alloc_cb(int fd, const char *mode, FILE *fp)
{
/*
* These symbols have conflicting declarations in upstream headers.
* Use uintptr_t and a cast to assign cleanly.
*/
extern uintptr_t _close_r;
extern uintptr_t _lseek_r;
extern uintptr_t _read_r;
extern uintptr_t _write_r;

__ASSERT_NO_MSG(mode != NULL);
__ASSERT_NO_MSG(fp != NULL);

fp->_flags = z_libc_sflags(mode);
fp->_file = fd;
fp->_cookie = (void *)fp;

*(uintptr_t *)&fp->_read = (uintptr_t)&_read_r;
*(uintptr_t *)&fp->_write = (uintptr_t)&_write_r;
*(uintptr_t *)&fp->_seek = (uintptr_t)&_lseek_r;
*(uintptr_t *)&fp->_close = (uintptr_t)&_close_r;
}

int zvfs_libc_file_get_fd(FILE *fp)
{
return fp->_file;
}
2 changes: 2 additions & 0 deletions lib/libc/picolibc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ zephyr_library_sources(
stdio.c
)

zephyr_library_sources_ifdef(CONFIG_ZVFS zvfs_libc.c)

zephyr_library_compile_options($<TARGET_PROPERTY:compiler,prohibit_lto>)

# define __LINUX_ERRNO_EXTENSIONS__ so we get errno defines like -ESHUTDOWN
Expand Down
8 changes: 8 additions & 0 deletions lib/libc/picolibc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,12 @@ config PICOLIBC_GLOBAL_ERRNO

endif # PICOLIBC_USE_MODULE

if ZVFS

config ZVFS_LIBC_FILE_SIZE
default 144 if 64BIT
default 80

endif # ZVFS

endif # PICOLIBC
30 changes: 25 additions & 5 deletions lib/libc/picolibc/stdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

#include "picolibc-hooks.h"
#include "stdio-bufio.h"

static LIBC_DATA int (*_stdout_hook)(int);

Expand All @@ -28,27 +29,46 @@ static int picolibc_put(char a, FILE *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);
#ifndef CONFIG_ZVFS
static LIBC_DATA FILE __stdout = FDEV_SETUP_STREAM(picolibc_put, NULL, NULL, _FDEV_SETUP_WRITE);
static LIBC_DATA FILE __stdin = FDEV_SETUP_STREAM(NULL, NULL, NULL, _FDEV_SETUP_READ);
#endif

#ifdef __strong_reference
#define STDIO_ALIAS(x) __strong_reference(stdout, x);
#else
#define STDIO_ALIAS(x) FILE *const x = &__stdout;
#endif

#ifndef CONFIG_ZVFS
FILE *const stdin = &__stdin;
FILE *const stdout = &__stdout;
STDIO_ALIAS(stderr);
#endif

void __stdout_hook_install(int (*hook)(int))
{
_stdout_hook = hook;
__stdout.flags |= _FDEV_SETUP_WRITE;
#ifdef CONFIG_ZVFS
stdout->put = picolibc_put;
stdout->flags |= _FDEV_SETUP_WRITE;

struct __file_bufio *bp = (struct __file_bufio *)stdout;

bp->ptr = INT_TO_POINTER(1 /* STDOUT_FILENO */);
bp->bflags |= _FDEV_SETUP_WRITE;
#endif
}

void __stdin_hook_install(unsigned char (*hook)(void))
{
__stdin.get = (int (*)(FILE *)) hook;
__stdin.flags |= _FDEV_SETUP_READ;
stdin->get = (int (*)(FILE *))hook;
#ifdef CONFIG_ZVFS
stdin->flags |= _FDEV_SETUP_READ;
struct __file_bufio *bp = (struct __file_bufio *)stdin;

bp->bflags |= _FDEV_SETUP_READ;
/* bp->get = (int (*)(FILE *))hook; */
bp->ptr = INT_TO_POINTER(0 /* STDIN_FILENO */);
#endif
}
82 changes: 82 additions & 0 deletions lib/libc/picolibc/zvfs_libc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2024 Tenstorrent AI ULC
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "stdio-bufio.h"

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#include <zephyr/sys/fdtable.h>
#include <zephyr/toolchain.h>

BUILD_ASSERT(CONFIG_ZVFS_LIBC_FILE_SIZE >= sizeof(struct __file_bufio),
"CONFIG_ZVFS_LIBC_FILE_SIZE must at least match size of FILE object");
BUILD_ASSERT(CONFIG_ZVFS_LIBC_FILE_ALIGN == __alignof(struct __file_bufio),
"CONFIG_ZVFS_LIBC_FILE_SIZE must match alignment of FILE object");

#define FDEV_SETUP_ZVFS(fd, buf, size, rwflags, bflags) \
FDEV_SETUP_BUFIO(fd, buf, size, zvfs_read_wrap, zvfs_write_wrap, zvfs_lseek, zvfs_close, \
rwflags, bflags)

/* FIXME: do not use ssize_t or off_t */
ssize_t zvfs_read(int fd, void *buf, size_t sz, const size_t *from_offset);
ssize_t zvfs_write(int fd, const void *buf, size_t sz, const size_t *from_offset);
off_t zvfs_lseek(int fd, off_t offset, int whence);
int zvfs_close(int fd);

static ssize_t zvfs_read_wrap(int fd, void *buf, size_t sz)
{
return zvfs_read(fd, buf, sz, NULL);
}

static ssize_t zvfs_write_wrap(int fd, const void *buf, size_t sz)
{
return zvfs_write(fd, buf, sz, NULL);
}

static int sflags(const char *mode)
{
int flags = 0;

if (mode == NULL) {
return 0;
}

switch (mode[0]) {
case 'r':
flags |= __SRD;
break;
case 'w':
flags |= __SWR;
break;
case 'a':
flags |= __SWR;
break;
}
if (mode[1] == '+') {
flags |= __SRD | __SWR;
}

return flags;
}

void zvfs_libc_file_alloc_cb(int fd, const char *mode, FILE *fp)
{
struct __file_bufio *const bf = (struct __file_bufio *)fp;

*bf = (struct __file_bufio)FDEV_SETUP_ZVFS(fd, (char *)(bf + 1), BUFSIZ, sflags(mode),
__BFALL);

__bufio_lock_init(&(bf->xfile.cfile.file));
}

int zvfs_libc_file_get_fd(FILE *fp)
{
const struct __file_bufio *const bf = (const struct __file_bufio *)fp;

return POINTER_TO_INT(bf->ptr);
}
Loading
Loading