kernel: mem_domain: init function to return error values
This changes k_mem_domain_init() to return error values instead of asserting when errors are encountered. This gives applications a chance to recover if needed. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
parent
2ffd49310a
commit
fb91ce2e21
13 changed files with 122 additions and 53 deletions
|
@ -121,9 +121,13 @@ struct k_mem_partition;
|
|||
* @param num_parts The number of array items of "parts" parameter.
|
||||
* @param parts An array of pointers to the memory partitions. Can be NULL
|
||||
* if num_parts is zero.
|
||||
*
|
||||
* @retval 0 if successful
|
||||
* @retval -EINVAL if invalid parameters supplied
|
||||
* @retval -ENOMEM if insufficient memory
|
||||
*/
|
||||
extern void k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts,
|
||||
struct k_mem_partition *parts[]);
|
||||
extern int k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts,
|
||||
struct k_mem_partition *parts[]);
|
||||
|
||||
/**
|
||||
* @brief Add a memory partition into a memory domain.
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <sys/__assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <spinlock.h>
|
||||
#include <sys/check.h>
|
||||
#include <sys/libc-hooks.h>
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
|
||||
|
@ -20,7 +21,6 @@ static uint8_t max_partitions;
|
|||
|
||||
struct k_mem_domain k_mem_domain_default;
|
||||
|
||||
#if __ASSERT_ON
|
||||
static bool check_add_partition(struct k_mem_domain *domain,
|
||||
struct k_mem_partition *part)
|
||||
{
|
||||
|
@ -84,19 +84,30 @@ static bool check_add_partition(struct k_mem_domain *domain,
|
|||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts,
|
||||
struct k_mem_partition *parts[])
|
||||
int k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts,
|
||||
struct k_mem_partition *parts[])
|
||||
{
|
||||
k_spinlock_key_t key;
|
||||
int ret = 0;
|
||||
|
||||
__ASSERT_NO_MSG(domain != NULL);
|
||||
__ASSERT(num_parts == 0U || parts != NULL,
|
||||
"parts array is NULL and num_parts is nonzero");
|
||||
__ASSERT(num_parts <= max_partitions,
|
||||
"num_parts of %d exceeds maximum allowable partitions (%d)",
|
||||
num_parts, max_partitions);
|
||||
CHECKIF(domain == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
CHECKIF(!(num_parts == 0U || parts != NULL)) {
|
||||
LOG_ERR("parts array is NULL and num_parts is nonzero");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
CHECKIF(!(num_parts <= max_partitions)) {
|
||||
LOG_ERR("num_parts of %d exceeds maximum allowable partitions (%d)",
|
||||
num_parts, max_partitions);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
key = k_spin_lock(&z_mem_domain_lock);
|
||||
|
||||
|
@ -105,25 +116,25 @@ void k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts,
|
|||
sys_dlist_init(&domain->mem_domain_q);
|
||||
|
||||
#ifdef CONFIG_ARCH_MEM_DOMAIN_DATA
|
||||
int ret = arch_mem_domain_init(domain);
|
||||
ret = arch_mem_domain_init(domain);
|
||||
|
||||
/* TODO propagate return values, see #24609.
|
||||
*
|
||||
* Not using an assertion here as this is a memory allocation error
|
||||
*/
|
||||
if (ret != 0) {
|
||||
LOG_ERR("architecture-specific initialization failed for domain %p with %d",
|
||||
domain, ret);
|
||||
k_panic();
|
||||
ret = -ENOMEM;
|
||||
goto unlock_out;
|
||||
}
|
||||
#endif
|
||||
if (num_parts != 0U) {
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0U; i < num_parts; i++) {
|
||||
__ASSERT(check_add_partition(domain, parts[i]),
|
||||
"invalid partition index %d (%p)",
|
||||
i, parts[i]);
|
||||
CHECKIF(!check_add_partition(domain, parts[i])) {
|
||||
LOG_ERR("invalid partition index %d (%p)",
|
||||
i, parts[i]);
|
||||
ret = -EINVAL;
|
||||
goto unlock_out;
|
||||
}
|
||||
|
||||
domain->partitions[i] = *parts[i];
|
||||
domain->num_partitions++;
|
||||
|
@ -133,7 +144,11 @@ void k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts,
|
|||
}
|
||||
}
|
||||
|
||||
unlock_out:
|
||||
k_spin_unlock(&z_mem_domain_lock, key);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void k_mem_domain_add_partition(struct k_mem_domain *domain,
|
||||
|
@ -269,7 +284,10 @@ void k_mem_domain_add_thread(struct k_mem_domain *domain, k_tid_t thread)
|
|||
|
||||
static int init_mem_domain_module(const struct device *arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ARG_UNUSED(arg);
|
||||
ARG_UNUSED(ret);
|
||||
|
||||
max_partitions = arch_mem_domain_max_partitions_get();
|
||||
/*
|
||||
|
@ -279,7 +297,9 @@ static int init_mem_domain_module(const struct device *arg)
|
|||
*/
|
||||
__ASSERT(max_partitions <= CONFIG_MAX_DOMAIN_PARTITIONS, "");
|
||||
|
||||
k_mem_domain_init(&k_mem_domain_default, 0, NULL);
|
||||
ret = k_mem_domain_init(&k_mem_domain_default, 0, NULL);
|
||||
__ASSERT(ret == 0, "failed to init default mem domain");
|
||||
|
||||
#ifdef Z_LIBC_PARTITION_EXISTS
|
||||
k_mem_domain_add_partition(&k_mem_domain_default, &z_libc_partition);
|
||||
#endif /* Z_LIBC_PARTITION_EXISTS */
|
||||
|
|
|
@ -524,6 +524,8 @@ void main(void)
|
|||
#endif
|
||||
|
||||
#if defined(CONFIG_USERSPACE)
|
||||
int ret;
|
||||
|
||||
struct k_mem_partition *parts[] = {
|
||||
#if Z_LIBC_PARTITION_EXISTS
|
||||
&z_libc_partition,
|
||||
|
@ -531,7 +533,10 @@ void main(void)
|
|||
&app_partition
|
||||
};
|
||||
|
||||
k_mem_domain_init(&app_domain, ARRAY_SIZE(parts), parts);
|
||||
ret = k_mem_domain_init(&app_domain, ARRAY_SIZE(parts), parts);
|
||||
__ASSERT(ret == 0, "k_mem_domain_init() failed %d", ret);
|
||||
ARG_UNUSED(ret);
|
||||
|
||||
k_mem_domain_add_thread(&app_domain, app_thread);
|
||||
k_thread_heap_assign(app_thread, &app_mem_pool);
|
||||
|
||||
|
|
|
@ -233,7 +233,10 @@ static void init_app(void)
|
|||
&app_partition
|
||||
};
|
||||
|
||||
k_mem_domain_init(&app_domain, ARRAY_SIZE(parts), parts);
|
||||
int ret = k_mem_domain_init(&app_domain, ARRAY_SIZE(parts), parts);
|
||||
|
||||
__ASSERT(ret == 0, "k_mem_domain_init() failed %d", ret);
|
||||
ARG_UNUSED(ret);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
|
||||
|
|
|
@ -131,7 +131,10 @@ static void init_app(void)
|
|||
&app_partition
|
||||
};
|
||||
|
||||
k_mem_domain_init(&app_domain, ARRAY_SIZE(parts), parts);
|
||||
int ret = k_mem_domain_init(&app_domain, ARRAY_SIZE(parts), parts);
|
||||
|
||||
__ASSERT(ret == 0, "k_mem_domain_init() failed %d", ret);
|
||||
ARG_UNUSED(ret);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) || \
|
||||
|
|
|
@ -335,7 +335,11 @@ static void log_demo_supervisor(void *p1, void *p2, void *p3)
|
|||
log_demo_thread(p1, p2, p3);
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
k_mem_domain_init(&app_domain, ARRAY_SIZE(app_parts), app_parts);
|
||||
int ret = k_mem_domain_init(&app_domain, ARRAY_SIZE(app_parts), app_parts);
|
||||
|
||||
__ASSERT(ret == 0, "k_mem_domain_init() failed %d\n", ret);
|
||||
ARG_UNUSED(ret);
|
||||
|
||||
k_mem_domain_add_thread(&app_domain, k_current_get());
|
||||
k_thread_user_mode_enter(log_demo_thread, p1, p2, p3);
|
||||
#endif
|
||||
|
|
|
@ -189,6 +189,7 @@ static void writeback_entry(void *p1, void *p2, void *p3)
|
|||
/* Supervisor mode setup function for application A */
|
||||
void app_a_entry(void *p1, void *p2, void *p3)
|
||||
{
|
||||
int ret;
|
||||
struct k_mem_partition *parts[] = {
|
||||
#if Z_LIBC_PARTITION_EXISTS
|
||||
&z_libc_partition,
|
||||
|
@ -207,7 +208,10 @@ void app_a_entry(void *p1, void *p2, void *p3)
|
|||
* partition, the shared partition, and any common libc partition
|
||||
* if it exists.
|
||||
*/
|
||||
k_mem_domain_init(&app_a_domain, ARRAY_SIZE(parts), parts);
|
||||
ret = k_mem_domain_init(&app_a_domain, ARRAY_SIZE(parts), parts);
|
||||
__ASSERT(ret == 0, "k_mem_domain_init failed %d", ret);
|
||||
ARG_UNUSED(ret);
|
||||
|
||||
k_mem_domain_add_thread(&app_a_domain, k_current_get());
|
||||
|
||||
/* Assign a resource pool to serve for kernel-side allocations on
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
* DO NOT USE THIS CODE FOR SECURITY
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/__assert.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "enc.h"
|
||||
/* the following definition name prefix is to avoid a conflict */
|
||||
|
@ -101,6 +104,7 @@ void main(void)
|
|||
struct k_mem_partition *enc_parts[] = {&enc_part, &red_part, &blk_part};
|
||||
struct k_mem_partition *pt_parts[] = {&user_part, &red_part};
|
||||
k_tid_t tPT, tENC, tCT;
|
||||
int ret;
|
||||
|
||||
fBUFIN = 0; /* clear flags */
|
||||
fBUFOUT = 0;
|
||||
|
@ -124,7 +128,11 @@ void main(void)
|
|||
k_thread_access_grant(tENC, &allforone);
|
||||
/* use K_FOREVER followed by k_thread_start*/
|
||||
printk("ENC Thread Created %p\n", tENC);
|
||||
k_mem_domain_init(&enc_domain, 3, enc_parts);
|
||||
|
||||
ret = k_mem_domain_init(&enc_domain, 3, enc_parts);
|
||||
__ASSERT(ret == 0, "k_mem_domain_init() on enc_domain failed %d", ret);
|
||||
ARG_UNUSED(ret);
|
||||
|
||||
printk("Partitions added to enc_domain\n");
|
||||
k_mem_domain_add_thread(&enc_domain, tENC);
|
||||
printk("enc_domain Created\n");
|
||||
|
@ -136,7 +144,10 @@ void main(void)
|
|||
K_FOREVER);
|
||||
k_thread_access_grant(tPT, &allforone);
|
||||
printk("PT Thread Created %p\n", tPT);
|
||||
k_mem_domain_init(&pt_domain, 2, pt_parts);
|
||||
|
||||
ret = k_mem_domain_init(&pt_domain, 2, pt_parts);
|
||||
__ASSERT(ret == 0, "k_mem_domain_init() on pt_domain failed %d", ret);
|
||||
|
||||
k_mem_domain_add_thread(&pt_domain, tPT);
|
||||
printk("pt_domain Created\n");
|
||||
|
||||
|
|
|
@ -42,12 +42,15 @@ void main(void)
|
|||
printk("Hello from %s!\n", CONFIG_BOARD);
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
int ret;
|
||||
struct k_mem_partition *mem_parts[] = {
|
||||
&footprint_mem_partition
|
||||
};
|
||||
|
||||
k_mem_domain_init(&footprint_mem_domain,
|
||||
ARRAY_SIZE(mem_parts), mem_parts);
|
||||
ret = k_mem_domain_init(&footprint_mem_domain,
|
||||
ARRAY_SIZE(mem_parts), mem_parts);
|
||||
__ASSERT_NO_MSG(ret == 0);
|
||||
ARG_UNUSED(ret);
|
||||
#endif /* CONFIG_USERSPACE */
|
||||
|
||||
run_thread_system();
|
||||
|
|
|
@ -100,9 +100,14 @@ static void test_thread_1_for_SU(void *p1, void *p2, void *p3)
|
|||
*/
|
||||
void test_permission_inheritance(void)
|
||||
{
|
||||
k_mem_domain_init(&inherit_mem_domain,
|
||||
ARRAY_SIZE(inherit_memory_partition_array),
|
||||
inherit_memory_partition_array);
|
||||
int ret;
|
||||
|
||||
ret = k_mem_domain_init(&inherit_mem_domain,
|
||||
ARRAY_SIZE(inherit_memory_partition_array),
|
||||
inherit_memory_partition_array);
|
||||
if (ret != 0) {
|
||||
ztest_test_fail();
|
||||
}
|
||||
|
||||
parent_tid = k_current_get();
|
||||
k_mem_domain_add_thread(&inherit_mem_domain, parent_tid);
|
||||
|
|
|
@ -53,7 +53,9 @@ void test_mem_domain_setup(void)
|
|||
CONFIG_MAX_DOMAIN_PARTITIONS, max_parts);
|
||||
zassert_true(num_rw_parts > 0, "no free memory partitions");
|
||||
|
||||
k_mem_domain_init(&test_domain, ARRAY_SIZE(parts), parts);
|
||||
zassert_equal(
|
||||
k_mem_domain_init(&test_domain, ARRAY_SIZE(parts), parts),
|
||||
0, "failed to initialize memory domain");
|
||||
|
||||
for (unsigned int i = 0; i < num_rw_parts; i++) {
|
||||
rw_parts[i].start = (uintptr_t)&rw_bufs[i];
|
||||
|
@ -207,7 +209,9 @@ K_MEM_PARTITION_DEFINE(no_access_part, no_access_buf, sizeof(no_access_buf),
|
|||
|
||||
static void mem_domain_init_entry(void *p1, void *p2, void *p3)
|
||||
{
|
||||
k_mem_domain_init(&no_access_domain, 0, NULL);
|
||||
zassert_equal(
|
||||
k_mem_domain_init(&no_access_domain, 0, NULL),
|
||||
0, "failed to initialize memory domain");
|
||||
}
|
||||
|
||||
static void mem_domain_add_partition_entry(void *p1, void *p2, void *p3)
|
||||
|
@ -469,10 +473,8 @@ void test_mem_domain_remove_part_fail(void)
|
|||
/**
|
||||
* @brief Test error case of initializing memory domain fail
|
||||
*
|
||||
* @details Try to initialize a domain with invalid partition, then see
|
||||
* if an expected fatal error happens.
|
||||
* And while the fatal error happened, the memory domain spinlock
|
||||
* is held, we need to release them to make other follow test case.
|
||||
* @details Try to initialize a domain with invalid partition.
|
||||
* k_mem_domain_init() should return non-zero.
|
||||
*
|
||||
* @ingroup kernel_memprotect_tests
|
||||
*/
|
||||
|
@ -480,18 +482,14 @@ void test_mem_domain_init_fail(void)
|
|||
{
|
||||
struct k_mem_partition *no_parts[] = {&ro_part, 0};
|
||||
|
||||
/* init another domain fail, expected fault happened */
|
||||
need_recover_spinlock = true;
|
||||
set_fault_valid(true);
|
||||
k_mem_domain_init(&test_domain_fail, ARRAY_SIZE(no_parts),
|
||||
no_parts);
|
||||
/* init another domain fail */
|
||||
need_recover_spinlock = false;
|
||||
set_fault_valid(false);
|
||||
|
||||
/* For acrh which not CONFIG_ARCH_MEM_DOMAIN_DATA, if assert is off,
|
||||
* it will reach here.
|
||||
*/
|
||||
#if !defined(CONFIG_ASSERT) && defined(CONFIG_ARCH_MEM_DOMAIN_DATA)
|
||||
zassert_unreachable("should not be here");
|
||||
#endif
|
||||
zassert_not_equal(
|
||||
k_mem_domain_init(&test_domain_fail, ARRAY_SIZE(no_parts),
|
||||
no_parts),
|
||||
0, "should fail to initialize memory domain");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -681,7 +681,11 @@ static void drop_user(volatile bool *to_modify)
|
|||
static void test_init_and_access_other_memdomain(void)
|
||||
{
|
||||
struct k_mem_partition *parts[] = { &ztest_mem_partition, &alt_part };
|
||||
k_mem_domain_init(&alternate_domain, ARRAY_SIZE(parts), parts);
|
||||
|
||||
zassert_equal(
|
||||
k_mem_domain_init(&alternate_domain, ARRAY_SIZE(parts), parts),
|
||||
0, "failed to initialize memory domain");
|
||||
|
||||
/* Switch to alternate_domain which does not have default_part that
|
||||
* contains default_bool. This should fault when we try to write it.
|
||||
*/
|
||||
|
|
|
@ -209,6 +209,7 @@ void test_tls_userspace(void)
|
|||
void test_main(void)
|
||||
{
|
||||
#ifdef CONFIG_USERSPACE
|
||||
int ret;
|
||||
unsigned int i;
|
||||
|
||||
struct k_mem_partition *parts[] = {
|
||||
|
@ -220,7 +221,11 @@ void test_main(void)
|
|||
};
|
||||
|
||||
parts[0] = &part_common;
|
||||
k_mem_domain_init(&dom_common, ARRAY_SIZE(parts), parts);
|
||||
|
||||
ret = k_mem_domain_init(&dom_common, ARRAY_SIZE(parts), parts);
|
||||
__ASSERT(ret == 0, "k_mem_domain_init() failed %d", ret);
|
||||
ARG_UNUSED(ret);
|
||||
|
||||
k_mem_domain_add_thread(&dom_common, k_current_get());
|
||||
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue