You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
2.4 KiB
96 lines
2.4 KiB
/* |
|
* Copyright (c) 2024 Arduino SA |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <string.h> |
|
#include <zephyr/llext/llext.h> |
|
#include <zephyr/llext/loader.h> |
|
#include <zephyr/internal/syscall_handler.h> |
|
#include <zephyr/kernel.h> |
|
|
|
#include <zephyr/logging/log.h> |
|
LOG_MODULE_DECLARE(llext, CONFIG_LLEXT_LOG_LEVEL); |
|
|
|
#include "llext_priv.h" |
|
|
|
ssize_t z_impl_llext_get_fn_table(struct llext *ext, bool is_init, void *buf, size_t buf_size) |
|
{ |
|
size_t table_size; |
|
|
|
if (!ext) { |
|
return -EINVAL; |
|
} |
|
|
|
if (is_init) { |
|
table_size = ext->mem_size[LLEXT_MEM_PREINIT] + |
|
ext->mem_size[LLEXT_MEM_INIT]; |
|
} else { |
|
table_size = ext->mem_size[LLEXT_MEM_FINI]; |
|
} |
|
|
|
if (buf) { |
|
char *byte_ptr = buf; |
|
|
|
if (buf_size < table_size) { |
|
return -ENOMEM; |
|
} |
|
|
|
if (is_init) { |
|
/* setup functions from preinit_array and init_array */ |
|
memcpy(byte_ptr, |
|
ext->mem[LLEXT_MEM_PREINIT], ext->mem_size[LLEXT_MEM_PREINIT]); |
|
memcpy(byte_ptr + ext->mem_size[LLEXT_MEM_PREINIT], |
|
ext->mem[LLEXT_MEM_INIT], ext->mem_size[LLEXT_MEM_INIT]); |
|
} else { |
|
/* cleanup functions from fini_array */ |
|
memcpy(byte_ptr, |
|
ext->mem[LLEXT_MEM_FINI], ext->mem_size[LLEXT_MEM_FINI]); |
|
} |
|
|
|
/* Sanity check: pointers in this table must map inside the |
|
* text region of the extension. If this fails, something went |
|
* wrong during the relocation process. |
|
* Using "char *" for these simplifies pointer arithmetic. |
|
*/ |
|
const char *text_start = ext->mem[LLEXT_MEM_TEXT]; |
|
const char *text_end = text_start + ext->mem_size[LLEXT_MEM_TEXT]; |
|
const char **fn_ptrs = buf; |
|
|
|
for (int i = 0; i < table_size / sizeof(void *); i++) { |
|
if (fn_ptrs[i] < text_start || fn_ptrs[i] >= text_end) { |
|
LOG_ERR("%s function %i (%p) outside text region", |
|
is_init ? "bringup" : "teardown", |
|
i, fn_ptrs[i]); |
|
return -EFAULT; |
|
} |
|
} |
|
} |
|
|
|
return table_size; |
|
} |
|
|
|
#ifdef CONFIG_USERSPACE |
|
|
|
static int ext_is_valid(struct llext *ext, void *arg) |
|
{ |
|
return ext == arg; |
|
} |
|
|
|
static inline ssize_t z_vrfy_llext_get_fn_table(struct llext *ext, bool is_init, |
|
void *buf, size_t size) |
|
{ |
|
/* Test that ext matches a loaded extension */ |
|
K_OOPS(llext_iterate(ext_is_valid, ext) == 0); |
|
|
|
if (buf) { |
|
/* Test that buf is a valid user-accessible pointer */ |
|
K_OOPS(K_SYSCALL_MEMORY_WRITE(buf, size)); |
|
} |
|
|
|
return z_impl_llext_get_fn_table(ext, is_init, buf, size); |
|
} |
|
#include <zephyr/syscalls/llext_get_fn_table_mrsh.c> |
|
|
|
#endif /* CONFIG_USERSPACE */
|
|
|