Skip to content

Commit be919d3

Browse files
Andrew Boiecarlescufi
authored andcommitted
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 <[email protected]>
1 parent 9f63a0a commit be919d3

File tree

4 files changed

+95
-30
lines changed

4 files changed

+95
-30
lines changed

include/kernel.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,27 @@ void k_object_access_all_grant(void *object);
352352
__syscall void *k_object_alloc(enum k_objects otype);
353353

354354
#ifdef CONFIG_DYNAMIC_OBJECTS
355+
/**
356+
* Allocate memory and install as a generic kernel object
357+
*
358+
* This is a low-level function to allocate some memory, and register that
359+
* allocated memory in the kernel object lookup tables with type K_OBJ_ANY.
360+
* Initialization state and thread permissions will be cleared. The
361+
* returned z_object's data value will be uninitialized.
362+
*
363+
* Most users will want to use k_object_alloc() instead.
364+
*
365+
* Memory allocated will be drawn from the calling thread's reasource pool
366+
* and may be freed later by passing the actual object pointer (found
367+
* in the returned z_object's 'name' member) to k_object_free().
368+
*
369+
* @param size Size of the allocated object
370+
* @return NULL on insufficient memory
371+
* @return A pointer to the associated z_object that is installed in the
372+
* kernel object tables
373+
*/
374+
struct z_object *z_dynamic_object_create(size_t size);
375+
355376
/**
356377
* Free a kernel object previously allocated with k_object_alloc()
357378
*
@@ -370,6 +391,14 @@ static inline void *z_impl_k_object_alloc(enum k_objects otype)
370391

371392
return NULL;
372393
}
394+
395+
static inline struct z_object *z_dynamic_object_create(size_t size)
396+
{
397+
ARG_UNUSED(size);
398+
399+
return NULL;
400+
}
401+
373402
/**
374403
* @brief Free an object
375404
*

kernel/userspace.c

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ const char *otype_to_str(enum k_objects otype)
7272
/* otype-to-str.h is generated automatically during build by
7373
* gen_kobject_list.py
7474
*/
75+
case K_OBJ_ANY:
76+
ret = "generic";
77+
break;
7578
#include <otype-to-str.h>
7679
default:
7780
ret = "?";
@@ -252,51 +255,81 @@ static void thread_idx_free(uintptr_t tidx)
252255
sys_bitfield_set_bit((mem_addr_t)_thread_idx_map, tidx);
253256
}
254257

255-
void *z_impl_k_object_alloc(enum k_objects otype)
258+
struct z_object *z_dynamic_object_create(size_t size)
256259
{
257260
struct dyn_obj *dyn_obj;
258-
uintptr_t tidx;
259-
260-
/* Stacks are not supported, we don't yet have mem pool APIs
261-
* to request memory that is aligned
262-
*/
263-
__ASSERT(otype > K_OBJ_ANY && otype < K_OBJ_LAST &&
264-
otype != K_OBJ_THREAD_STACK_ELEMENT,
265-
"bad object type requested");
266261

267-
dyn_obj = z_thread_malloc(sizeof(*dyn_obj) + obj_size_get(otype));
262+
dyn_obj = z_thread_malloc(sizeof(*dyn_obj) + size);
268263
if (dyn_obj == NULL) {
269-
LOG_WRN("could not allocate kernel object");
264+
LOG_ERR("could not allocate kernel object, out of memory");
270265
return NULL;
271266
}
272267

273-
dyn_obj->kobj.name = (char *)&dyn_obj->data;
274-
dyn_obj->kobj.type = otype;
275-
dyn_obj->kobj.flags = K_OBJ_FLAG_ALLOC;
268+
dyn_obj->kobj.name = &dyn_obj->data;
269+
dyn_obj->kobj.type = K_OBJ_ANY;
270+
dyn_obj->kobj.flags = 0;
276271
(void)memset(dyn_obj->kobj.perms, 0, CONFIG_MAX_THREAD_BYTES);
277272

278-
/* Need to grab a new thread index for k_thread */
279-
if (otype == K_OBJ_THREAD) {
273+
k_spinlock_key_t key = k_spin_lock(&lists_lock);
274+
275+
rb_insert(&obj_rb_tree, &dyn_obj->node);
276+
sys_dlist_append(&obj_list, &dyn_obj->obj_list);
277+
k_spin_unlock(&lists_lock, key);
278+
279+
return &dyn_obj->kobj;
280+
}
281+
282+
void *z_impl_k_object_alloc(enum k_objects otype)
283+
{
284+
struct z_object *zo;
285+
uintptr_t tidx;
286+
287+
if (otype <= K_OBJ_ANY || otype >= K_OBJ_LAST) {
288+
LOG_ERR("bad object type %d requested", otype);
289+
return NULL;
290+
}
291+
292+
switch (otype) {
293+
case K_OBJ_THREAD:
280294
if (!thread_idx_alloc(&tidx)) {
281-
k_free(dyn_obj);
295+
LOG_ERR("out of free thread indexes");
282296
return NULL;
283297
}
298+
break;
299+
/* The following are currently not allowed at all */
300+
case K_OBJ_FUTEX: /* Lives in user memory */
301+
case K_OBJ_SYS_MUTEX: /* Lives in user memory */
302+
case K_OBJ_THREAD_STACK_ELEMENT: /* No aligned allocator */
303+
case K_OBJ_NET_SOCKET: /* Indeterminate size */
304+
LOG_ERR("forbidden object type '%s' requested",
305+
otype_to_str(otype));
306+
return NULL;
307+
default:
308+
/* Remainder within bounds are permitted */
309+
break;
310+
}
284311

285-
dyn_obj->kobj.data.thread_id = tidx;
312+
zo = z_dynamic_object_create(obj_size_get(otype));
313+
if (zo == NULL) {
314+
return NULL;
315+
}
316+
zo->type = otype;
317+
318+
if (otype == K_OBJ_THREAD) {
319+
zo->data.thread_id = tidx;
286320
}
287321

288322
/* The allocating thread implicitly gets permission on kernel objects
289323
* that it allocates
290324
*/
291-
z_thread_perms_set(&dyn_obj->kobj, _current);
325+
z_thread_perms_set(zo, _current);
292326

293-
k_spinlock_key_t key = k_spin_lock(&lists_lock);
294-
295-
rb_insert(&obj_rb_tree, &dyn_obj->node);
296-
sys_dlist_append(&obj_list, &dyn_obj->obj_list);
297-
k_spin_unlock(&lists_lock, key);
327+
/* Activates reference counting logic for automatic disposal when
328+
* all permissions have been revoked
329+
*/
330+
zo->flags |= K_OBJ_FLAG_ALLOC;
298331

299-
return dyn_obj->kobj.name;
332+
return zo->name;
300333
}
301334

302335
void k_object_free(void *obj)
@@ -508,6 +541,12 @@ void z_dump_object_error(int retval, void *obj, struct z_object *ko,
508541
switch (retval) {
509542
case -EBADF:
510543
LOG_ERR("%p is not a valid %s", obj, otype_to_str(otype));
544+
if (ko == NULL) {
545+
LOG_ERR("address is not a known kernel object");
546+
} else {
547+
LOG_ERR("address is actually a %s",
548+
otype_to_str(ko->type));
549+
}
511550
break;
512551
case -EPERM:
513552
dump_permission_error(ko);

kernel/userspace_handler.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,6 @@ static inline void z_vrfy_k_object_release(void *object)
6262

6363
static inline void *z_vrfy_k_object_alloc(enum k_objects otype)
6464
{
65-
Z_OOPS(Z_SYSCALL_VERIFY_MSG(otype > K_OBJ_ANY && otype < K_OBJ_LAST &&
66-
otype != K_OBJ_THREAD_STACK_ELEMENT,
67-
"bad object type %d requested", otype));
68-
6965
return z_impl_k_object_alloc(otype);
7066
}
7167
#include <syscalls/k_object_alloc_mrsh.c>

scripts/gen_kobject_list.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@
7979
# the object to be located in user-accessible memory.
8080
#
8181
# - The third items is a boolean indicating whether this item can be
82-
# dynamically allocated with k_object_alloc()
82+
# dynamically allocated with k_object_alloc(). Keep this in sync with
83+
# the switch statement in z_impl_k_object_alloc().
8384
#
8485
# Key names in all caps do not correspond to a specific data type but instead
8586
# indicate that objects of its type are of a family of compatible data

0 commit comments

Comments
 (0)