userspace: improve dynamic object allocation

We now have a low-level function z_dynamic_object_create()
which is not a system call and is used for installing
kernel objects that are not supported by k_object_alloc().

Checking for valid object type enumeration values moved
completely to the implementation function.

A few debug messages and comments were improved.

Futexes and sys_mutexes are now properly excluded from
dynamic generation.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2020-05-29 17:49:02 -07:00 committed by Carles Cufí
commit be919d3bf7
4 changed files with 100 additions and 35 deletions

View file

@ -352,6 +352,27 @@ void k_object_access_all_grant(void *object);
__syscall void *k_object_alloc(enum k_objects otype);
#ifdef CONFIG_DYNAMIC_OBJECTS
/**
* Allocate memory and install as a generic kernel object
*
* This is a low-level function to allocate some memory, and register that
* allocated memory in the kernel object lookup tables with type K_OBJ_ANY.
* Initialization state and thread permissions will be cleared. The
* returned z_object's data value will be uninitialized.
*
* Most users will want to use k_object_alloc() instead.
*
* Memory allocated will be drawn from the calling thread's reasource pool
* and may be freed later by passing the actual object pointer (found
* in the returned z_object's 'name' member) to k_object_free().
*
* @param size Size of the allocated object
* @return NULL on insufficient memory
* @return A pointer to the associated z_object that is installed in the
* kernel object tables
*/
struct z_object *z_dynamic_object_create(size_t size);
/**
* Free a kernel object previously allocated with k_object_alloc()
*
@ -370,6 +391,14 @@ static inline void *z_impl_k_object_alloc(enum k_objects otype)
return NULL;
}
static inline struct z_object *z_dynamic_object_create(size_t size)
{
ARG_UNUSED(size);
return NULL;
}
/**
* @brief Free an object
*

View file

@ -72,6 +72,9 @@ const char *otype_to_str(enum k_objects otype)
/* otype-to-str.h is generated automatically during build by
* gen_kobject_list.py
*/
case K_OBJ_ANY:
ret = "generic";
break;
#include <otype-to-str.h>
default:
ret = "?";
@ -252,51 +255,81 @@ static void thread_idx_free(uintptr_t tidx)
sys_bitfield_set_bit((mem_addr_t)_thread_idx_map, tidx);
}
void *z_impl_k_object_alloc(enum k_objects otype)
struct z_object *z_dynamic_object_create(size_t size)
{
struct dyn_obj *dyn_obj;
uintptr_t tidx;
/* Stacks are not supported, we don't yet have mem pool APIs
* to request memory that is aligned
*/
__ASSERT(otype > K_OBJ_ANY && otype < K_OBJ_LAST &&
otype != K_OBJ_THREAD_STACK_ELEMENT,
"bad object type requested");
dyn_obj = z_thread_malloc(sizeof(*dyn_obj) + obj_size_get(otype));
dyn_obj = z_thread_malloc(sizeof(*dyn_obj) + size);
if (dyn_obj == NULL) {
LOG_WRN("could not allocate kernel object");
LOG_ERR("could not allocate kernel object, out of memory");
return NULL;
}
dyn_obj->kobj.name = (char *)&dyn_obj->data;
dyn_obj->kobj.type = otype;
dyn_obj->kobj.flags = K_OBJ_FLAG_ALLOC;
dyn_obj->kobj.name = &dyn_obj->data;
dyn_obj->kobj.type = K_OBJ_ANY;
dyn_obj->kobj.flags = 0;
(void)memset(dyn_obj->kobj.perms, 0, CONFIG_MAX_THREAD_BYTES);
/* Need to grab a new thread index for k_thread */
if (otype == K_OBJ_THREAD) {
if (!thread_idx_alloc(&tidx)) {
k_free(dyn_obj);
return NULL;
}
dyn_obj->kobj.data.thread_id = tidx;
}
/* The allocating thread implicitly gets permission on kernel objects
* that it allocates
*/
z_thread_perms_set(&dyn_obj->kobj, _current);
k_spinlock_key_t key = k_spin_lock(&lists_lock);
rb_insert(&obj_rb_tree, &dyn_obj->node);
sys_dlist_append(&obj_list, &dyn_obj->obj_list);
k_spin_unlock(&lists_lock, key);
return dyn_obj->kobj.name;
return &dyn_obj->kobj;
}
void *z_impl_k_object_alloc(enum k_objects otype)
{
struct z_object *zo;
uintptr_t tidx;
if (otype <= K_OBJ_ANY || otype >= K_OBJ_LAST) {
LOG_ERR("bad object type %d requested", otype);
return NULL;
}
switch (otype) {
case K_OBJ_THREAD:
if (!thread_idx_alloc(&tidx)) {
LOG_ERR("out of free thread indexes");
return NULL;
}
break;
/* The following are currently not allowed at all */
case K_OBJ_FUTEX: /* Lives in user memory */
case K_OBJ_SYS_MUTEX: /* Lives in user memory */
case K_OBJ_THREAD_STACK_ELEMENT: /* No aligned allocator */
case K_OBJ_NET_SOCKET: /* Indeterminate size */
LOG_ERR("forbidden object type '%s' requested",
otype_to_str(otype));
return NULL;
default:
/* Remainder within bounds are permitted */
break;
}
zo = z_dynamic_object_create(obj_size_get(otype));
if (zo == NULL) {
return NULL;
}
zo->type = otype;
if (otype == K_OBJ_THREAD) {
zo->data.thread_id = tidx;
}
/* The allocating thread implicitly gets permission on kernel objects
* that it allocates
*/
z_thread_perms_set(zo, _current);
/* Activates reference counting logic for automatic disposal when
* all permissions have been revoked
*/
zo->flags |= K_OBJ_FLAG_ALLOC;
return zo->name;
}
void k_object_free(void *obj)
@ -508,6 +541,12 @@ void z_dump_object_error(int retval, void *obj, struct z_object *ko,
switch (retval) {
case -EBADF:
LOG_ERR("%p is not a valid %s", obj, otype_to_str(otype));
if (ko == NULL) {
LOG_ERR("address is not a known kernel object");
} else {
LOG_ERR("address is actually a %s",
otype_to_str(ko->type));
}
break;
case -EPERM:
dump_permission_error(ko);

View file

@ -62,10 +62,6 @@ static inline void z_vrfy_k_object_release(void *object)
static inline void *z_vrfy_k_object_alloc(enum k_objects otype)
{
Z_OOPS(Z_SYSCALL_VERIFY_MSG(otype > K_OBJ_ANY && otype < K_OBJ_LAST &&
otype != K_OBJ_THREAD_STACK_ELEMENT,
"bad object type %d requested", otype));
return z_impl_k_object_alloc(otype);
}
#include <syscalls/k_object_alloc_mrsh.c>

View file

@ -79,7 +79,8 @@ from collections import OrderedDict
# the object to be located in user-accessible memory.
#
# - The third items is a boolean indicating whether this item can be
# dynamically allocated with k_object_alloc()
# dynamically allocated with k_object_alloc(). Keep this in sync with
# the switch statement in z_impl_k_object_alloc().
#
# Key names in all caps do not correspond to a specific data type but instead
# indicate that objects of its type are of a family of compatible data